Browse Source

commit de 25-07-2025

28062025_02
andrymodeste 4 months ago
parent
commit
5ad019d35e
  1. 87
      lib/Components/appDrawer.dart
  2. 85
      lib/Services/stock_managementDatabase.dart
  3. 1
      lib/Views/approbation_sorties_page.dart
  4. 2
      lib/Views/commandManagement.dart
  5. 87
      lib/Views/demande_sortie_personnelle_page.dart
  6. 44
      lib/Views/historique.dart
  7. 2
      lib/config/DatabaseConfig.dart
  8. 31
      lib/controller/HistoryController.dart
  9. 14
      lib/controller/userController.dart
  10. 24
      lib/main.dart

87
lib/Components/appDrawer.dart

@ -109,14 +109,15 @@ class CustomDrawer extends StatelessWidget {
}); });
} else { } else {
invalidMenus.add(menu); invalidMenus.add(menu);
print("⚠️ Menu invalide ignoré dans CustomDrawer: id=$id, name='$name', route='$route'"); // print("⚠️ Menu invalide ignoré dans CustomDrawer: id=$id, name='$name', route='$route'");
} }
} }
// NOUVEAU: Ajouter le menu Demande Assignation pour Super Admin uniquement // NOUVEAU: Ajouter le menu Demande Assignation pour Super Admin uniquement
if (userController.role == 'Super Admin') { if (userController.role == 'Super Admin') {
// Vérifier si le menu n'existe pas déjà // Vérifier si le menu n'existe pas déjà
final bool demandeAssignationExists = validMenus.any((menu) => menu['route'] == '/demande-assignation'); final bool demandeAssignationExists =
validMenus.any((menu) => menu['route'] == '/demande-assignation');
if (!demandeAssignationExists) { if (!demandeAssignationExists) {
validMenus.add({ validMenus.add({
@ -124,7 +125,7 @@ class CustomDrawer extends StatelessWidget {
'name': 'Demande Assignation', 'name': 'Demande Assignation',
'route': '/demande-assignation', 'route': '/demande-assignation',
}); });
print("✅ Menu 'Demande Assignation' ajouté pour Super Admin"); // print("✅ Menu 'Demande Assignation' ajouté pour Super Admin");
} }
} }
@ -133,7 +134,8 @@ class CustomDrawer extends StatelessWidget {
// Afficher les statistiques de validation // Afficher les statistiques de validation
if (invalidMenus.isNotEmpty) { if (invalidMenus.isNotEmpty) {
print("📊 CustomDrawer: ${validMenus.length} menus valides, ${invalidMenus.length} invalides"); // print(
// "📊 CustomDrawer: ${validMenus.length} menus valides, ${invalidMenus.length} invalides");
} }
if (validMenus.isEmpty) { if (validMenus.isEmpty) {
@ -158,7 +160,8 @@ class CustomDrawer extends StatelessWidget {
final deduplicatedMenus = uniqueMenus.values.toList(); final deduplicatedMenus = uniqueMenus.values.toList();
if (deduplicatedMenus.length != validMenus.length) { if (deduplicatedMenus.length != validMenus.length) {
print("🔧 CustomDrawer: ${validMenus.length - deduplicatedMenus.length} doublons supprimés"); // print(
// "🔧 CustomDrawer: ${validMenus.length - deduplicatedMenus.length} doublons supprimés");
} }
// Organiser les menus par catégories // Organiser les menus par catégories
@ -173,7 +176,9 @@ class CustomDrawer extends StatelessWidget {
}; };
// Accueil toujours en premier // Accueil toujours en premier
final accueilMenu = deduplicatedMenus.where((menu) => menu['route'] == '/accueil').firstOrNull; final accueilMenu = deduplicatedMenus
.where((menu) => menu['route'] == '/accueil')
.firstOrNull;
if (accueilMenu != null) { if (accueilMenu != null) {
drawerItems.add(_buildDrawerItemFromMenu(accueilMenu)); drawerItems.add(_buildDrawerItemFromMenu(accueilMenu));
} }
@ -184,7 +189,7 @@ class CustomDrawer extends StatelessWidget {
// Validation supplémentaire avant categorisation // Validation supplémentaire avant categorisation
if (route.isEmpty) { if (route.isEmpty) {
print("⚠️ Route vide ignorée: ${menu['name']}"); // print("⚠️ Route vide ignorée: ${menu['name']}");
continue; continue;
} }
@ -224,7 +229,7 @@ class CustomDrawer extends StatelessWidget {
break; break;
default: default:
// Menu non catégorisé // Menu non catégorisé
print("⚠️ Menu non catégorisé: $route"); // print("⚠️ Menu non catégorisé: $route");
break; break;
} }
} }
@ -233,7 +238,8 @@ class CustomDrawer extends StatelessWidget {
categorizedMenus.forEach((categoryName, menus) { categorizedMenus.forEach((categoryName, menus) {
if (menus.isNotEmpty) { if (menus.isNotEmpty) {
// Afficher la catégorie SUPER ADMIN seulement pour les Super Admin // Afficher la catégorie SUPER ADMIN seulement pour les Super Admin
if (categoryName == 'SUPER ADMIN' && userController.role != 'Super Admin') { if (categoryName == 'SUPER ADMIN' &&
userController.role != 'Super Admin') {
return; // Skip cette catégorie return; // Skip cette catégorie
} }
@ -250,37 +256,42 @@ class CustomDrawer extends StatelessWidget {
/// NOUVEAU: Méthode pour ajouter les menus de sorties personnelles /// NOUVEAU: Méthode pour ajouter les menus de sorties personnelles
void _addSortiesPersonnellesMenus(List<Map<String, dynamic>> validMenus) { void _addSortiesPersonnellesMenus(List<Map<String, dynamic>> validMenus) {
// Menu Demande Sortie Personnelle - Accessible à tous les utilisateurs connectés // Menu Demande Sortie Personnelle - Accessible à tous les utilisateurs connectés
final bool demandeSortieExists = validMenus.any((menu) => menu['route'] == '/demande-sortie-personnelle'); final bool demandeSortieExists = validMenus
.any((menu) => menu['route'] == '/demande-sortie-personnelle');
if (!demandeSortieExists) { if (!demandeSortieExists) {
validMenus.add({ validMenus.add({
'id': 'demande_sortie_personnelle', 'id': 'demande_sortie_personnelle',
'name': 'Demande sortie personnelle', 'name': 'Demande sortie personnelle',
'route': '/demande-sortie-personnelle', 'route': '/demande-sortie-personnelle',
}); });
print("✅ Menu 'Demande sortie personnelle' ajouté pour tous les utilisateurs"); // print(
// "✅ Menu 'Demande sortie personnelle' ajouté pour tous les utilisateurs");
} }
// Menu Historique Sorties Personnelles - Accessible à tous les utilisateurs connectés // Menu Historique Sorties Personnelles - Accessible à tous les utilisateurs connectés
final bool historiqueSortiesExists = validMenus.any((menu) => menu['route'] == '/historique-sorties-personnelles'); final bool historiqueSortiesExists = validMenus
.any((menu) => menu['route'] == '/historique-sorties-personnelles');
if (!historiqueSortiesExists) { if (!historiqueSortiesExists) {
validMenus.add({ validMenus.add({
'id': 'historique_sorties_personnelles', 'id': 'historique_sorties_personnelles',
'name': 'Historique sorties personnelles', 'name': 'Historique sorties personnelles',
'route': '/historique-sorties-personnelles', 'route': '/historique-sorties-personnelles',
}); });
print("✅ Menu 'Historique sorties personnelles' ajouté pour tous les utilisateurs"); // print(
// "✅ Menu 'Historique sorties personnelles' ajouté pour tous les utilisateurs");
} }
// Menu Approbation Sorties - Accessible SEULEMENT aux Super Admin // Menu Approbation Sorties - Accessible SEULEMENT aux Super Admin
if (userController.role == 'Super Admin') { if (userController.role == 'Super Admin') {
final bool approbationSortiesExists = validMenus.any((menu) => menu['route'] == '/approbation-sorties'); final bool approbationSortiesExists =
validMenus.any((menu) => menu['route'] == '/approbation-sorties');
if (!approbationSortiesExists) { if (!approbationSortiesExists) {
validMenus.add({ validMenus.add({
'id': 'approbation_sorties', 'id': 'approbation_sorties',
'name': 'Approuver sorties', 'name': 'Approuver sorties',
'route': '/approbation-sorties', 'route': '/approbation-sorties',
}); });
print("✅ Menu 'Approuver sorties' ajouté pour Super Admin"); // print("✅ Menu 'Approuver sorties' ajouté pour Super Admin");
} }
} }
} }
@ -292,7 +303,8 @@ class CustomDrawer extends StatelessWidget {
final routeObj = menu['route']; final routeObj = menu['route'];
if (nameObj == null || routeObj == null) { if (nameObj == null || routeObj == null) {
print("⚠️ Menu invalide dans _buildDrawerItemFromMenu: name=$nameObj, route=$routeObj"); // print(
// "⚠️ Menu invalide dans _buildDrawerItemFromMenu: name=$nameObj, route=$routeObj");
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
@ -300,7 +312,7 @@ class CustomDrawer extends StatelessWidget {
final String route = routeObj.toString(); final String route = routeObj.toString();
if (name.isEmpty || route.isEmpty) { if (name.isEmpty || route.isEmpty) {
print("⚠️ Menu avec valeurs vides: name='$name', route='$route'"); // print("⚠️ Menu avec valeurs vides: name='$name', route='$route'");
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
@ -391,11 +403,12 @@ class CustomDrawer extends StatelessWidget {
final routeData = routeMapping[route]; final routeData = routeMapping[route];
if (routeData == null) { if (routeData == null) {
print("⚠️ Route non reconnue: '$route' pour le menu '$name'"); // print("⚠️ Route non reconnue: '$route' pour le menu '$name'");
return ListTile( return ListTile(
leading: const Icon(Icons.help_outline, color: Colors.grey), leading: const Icon(Icons.help_outline, color: Colors.grey),
title: Text(name), title: Text(name),
subtitle: Text("Route: $route", style: const TextStyle(fontSize: 10, color: Colors.grey)), subtitle: Text("Route: $route",
style: const TextStyle(fontSize: 10, color: Colors.grey)),
onTap: () { onTap: () {
Get.snackbar( Get.snackbar(
"Route non configurée", "Route non configurée",
@ -417,7 +430,8 @@ class CustomDrawer extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
// NOUVEAU: Badge Super Admin pour les menus réservés // NOUVEAU: Badge Super Admin pour les menus réservés
if ((route == '/demande-assignation' || route == '/approbation-sorties') && if ((route == '/demande-assignation' ||
route == '/approbation-sorties') &&
userController.role == 'Super Admin') ...[ userController.role == 'Super Admin') ...[
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
@ -437,7 +451,8 @@ class CustomDrawer extends StatelessWidget {
const SizedBox(width: 4), const SizedBox(width: 4),
], ],
// NOUVEAU: Badge "Tous" pour les menus accessibles à tous // NOUVEAU: Badge "Tous" pour les menus accessibles à tous
if (route == '/demande-sortie-personnelle' || route == '/historique-sorties-personnelles') ...[ if (route == '/demande-sortie-personnelle' ||
route == '/historique-sorties-personnelles') ...[
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -544,7 +559,9 @@ class CustomDrawer extends StatelessWidget {
Row( Row(
children: [ children: [
Text( Text(
controller.role.isNotEmpty ? controller.role : 'Aucun rôle', controller.role.isNotEmpty
? controller.role
: 'Aucun rôle',
style: const TextStyle( style: const TextStyle(
color: Colors.white70, color: Colors.white70,
fontSize: 12, fontSize: 12,
@ -554,7 +571,8 @@ class CustomDrawer extends StatelessWidget {
if (controller.role == 'Super Admin') ...[ if (controller.role == 'Super Admin') ...[
const SizedBox(width: 8), const SizedBox(width: 8),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), padding: const EdgeInsets.symmetric(
horizontal: 6, vertical: 2),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.red.shade600, color: Colors.red.shade600,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
@ -586,8 +604,12 @@ class CustomDrawer extends StatelessWidget {
Row( Row(
children: [ children: [
Icon( Icon(
controller.isCacheReady ? Icons.check_circle : Icons.hourglass_empty, controller.isCacheReady
color: controller.isCacheReady ? Colors.green : Colors.orange, ? Icons.check_circle
: Icons.hourglass_empty,
color: controller.isCacheReady
? Colors.green
: Colors.orange,
size: 12, size: 12,
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
@ -604,7 +626,8 @@ class CustomDrawer extends StatelessWidget {
), ),
), ),
// Bouton de rafraîchissement pour les admins // Bouton de rafraîchissement pour les admins
if (controller.role == 'Super Admin' || controller.role == 'Admin') ...[ if (controller.role == 'Super Admin' ||
controller.role == 'Admin') ...[
IconButton( IconButton(
icon: const Icon(Icons.refresh, color: Colors.white70, size: 20), icon: const Icon(Icons.refresh, color: Colors.white70, size: 20),
onPressed: () async { onPressed: () async {
@ -630,14 +653,16 @@ class CustomDrawer extends StatelessWidget {
// 🔧 Bouton de debug (à supprimer en production) // 🔧 Bouton de debug (à supprimer en production)
if (controller.role == 'Super Admin') ...[ if (controller.role == 'Super Admin') ...[
IconButton( IconButton(
icon: const Icon(Icons.bug_report, color: Colors.white70, size: 18), icon:
const Icon(Icons.bug_report, color: Colors.white70, size: 18),
onPressed: () { onPressed: () {
// Debug des menus // Debug des menus
final menus = controller.getUserMenus(); final menus = controller.getUserMenus();
String debugInfo = "MENUS DEBUG:\n"; String debugInfo = "MENUS DEBUG:\n";
for (var i = 0; i < menus.length; i++) { for (var i = 0; i < menus.length; i++) {
final menu = menus[i]; final menu = menus[i];
debugInfo += "[$i] ID:${menu['id']}, Name:'${menu['name']}', Route:'${menu['route']}'\n"; debugInfo +=
"[$i] ID:${menu['id']}, Name:'${menu['name']}', Route:'${menu['route']}'\n";
} }
// NOUVEAU: Ajouter info sur les menus sorties personnelles // NOUVEAU: Ajouter info sur les menus sorties personnelles
@ -645,13 +670,15 @@ class CustomDrawer extends StatelessWidget {
debugInfo += "Rôle actuel: ${controller.role}\n"; debugInfo += "Rôle actuel: ${controller.role}\n";
debugInfo += "Menu Demande Sortie: Accessible à tous\n"; debugInfo += "Menu Demande Sortie: Accessible à tous\n";
debugInfo += "Menu Historique: Accessible à tous\n"; debugInfo += "Menu Historique: Accessible à tous\n";
debugInfo += "Menu Approbation: ${controller.role == 'Super Admin' ? 'Accessible (Super Admin)' : 'Non accessible'}\n"; debugInfo +=
"Menu Approbation: ${controller.role == 'Super Admin' ? 'Accessible (Super Admin)' : 'Non accessible'}\n";
Get.dialog( Get.dialog(
AlertDialog( AlertDialog(
title: const Text("Debug Menus"), title: const Text("Debug Menus"),
content: SingleChildScrollView( content: SingleChildScrollView(
child: Text(debugInfo, style: const TextStyle(fontSize: 12)), child:
Text(debugInfo, style: const TextStyle(fontSize: 12)),
), ),
actions: [ actions: [
TextButton( TextButton(

85
lib/Services/stock_managementDatabase.dart

@ -1447,58 +1447,61 @@ class AppDatabase {
// --- TRANSACTIONS COMPLEXES --- // --- TRANSACTIONS COMPLEXES ---
// Méthode pour créer une commande complète avec remises // Méthode pour créer une commande complète avec remises
Future<int> createCommandeComplete( Future<int> createCommandeComplete(
Client client, Commande commande, List<DetailCommande> details) async { Client client, Commande commande, List<DetailCommande> details) async {
final db = await database; final db = await database;
try {
await db.query('START TRANSACTION');
// 1. Créer ou récupérer le client try {
final existingOrNewClient = await createOrGetClient(client); await db.query('START TRANSACTION');
final clientId = existingOrNewClient.id!;
// 2. Créer la commande // 1. Créer ou récupérer le client
final commandeMap = commande.toMap(); final existingOrNewClient = await createOrGetClient(client);
commandeMap.remove('id'); final clientId = existingOrNewClient.id!;
commandeMap['clientId'] = clientId;
final commandeFields = commandeMap.keys.join(', '); // 2. Créer la commande
final commandePlaceholders = final commandeMap = commande.toMap();
List.filled(commandeMap.length, '?').join(', '); commandeMap.remove('id');
commandeMap['clientId'] = clientId;
final commandeResult = await db.query( final commandeFields = commandeMap.keys.join(', ');
'INSERT INTO commandes ($commandeFields) VALUES ($commandePlaceholders)', final commandePlaceholders = List.filled(commandeMap.length, '?').join(', ');
commandeMap.values.toList());
final commandeId = commandeResult.insertId!;
// 3. Créer les détails de commande avec remises final commandeResult = await db.query(
for (final detail in details) { 'INSERT INTO commandes ($commandeFields) VALUES ($commandePlaceholders)',
final detailMap = detail.toMap(); commandeMap.values.toList(),
detailMap.remove('id'); );
detailMap['commandeId'] = commandeId; final commandeId = commandeResult.insertId!;
final detailFields = detailMap.keys.join(', '); // 3. Créer les détails de commande avec remises
final detailPlaceholders = for (final detail in details) {
List.filled(detailMap.length, '?').join(', '); final detailMap = detail.toMap();
detailMap.remove('id');
detailMap['commandeId'] = commandeId;
await db.query( final detailFields = detailMap.keys.join(', ');
'INSERT INTO details_commandes ($detailFields) VALUES ($detailPlaceholders)', final detailPlaceholders = List.filled(detailMap.length, '?').join(', ');
detailMap.values.toList());
// 4. Mettre à jour le stock await db.query(
await db.query('UPDATE products SET stock = stock - ? WHERE id = ?', 'INSERT INTO details_commandes ($detailFields) VALUES ($detailPlaceholders)',
[detail.quantite, detail.produitId]); detailMap.values.toList(),
} );
await db.query('COMMIT'); // 4. Mettre à jour le stock
return commandeId; await db.query(
} catch (e) { 'UPDATE products SET stock = stock - ? WHERE id = ?',
await db.query('ROLLBACK'); [detail.quantite, detail.produitId],
print("Erreur lors de la création de la commande complète: $e"); );
rethrow;
} }
await db.query('COMMIT');
return commandeId;
} catch (e) {
await db.query('ROLLBACK');
print("Erreur lors de la création de la commande complète: $e");
rethrow;
} }
}
// Méthode pour mettre à jour un détail de commande (utile pour modifier les remises) // Méthode pour mettre à jour un détail de commande (utile pour modifier les remises)
Future<int> updateDetailCommande(DetailCommande detail) async { Future<int> updateDetailCommande(DetailCommande detail) async {

1
lib/Views/approbation_sorties_page.dart

@ -52,6 +52,7 @@ class _ApprobationSortiesPageState extends State<ApprobationSortiesPage> {
Text('Quantité: ${sortie['quantite']}'), Text('Quantité: ${sortie['quantite']}'),
Text('Demandeur: ${sortie['admin_nom']}'), Text('Demandeur: ${sortie['admin_nom']}'),
Text('Motif: ${sortie['motif']}'), Text('Motif: ${sortie['motif']}'),
Text('Note: ${sortie['notes']}'),
const SizedBox(height: 16), const SizedBox(height: 16),
const Text( const Text(
'Confirmer l\'approbation de cette demande de sortie personnelle ?', 'Confirmer l\'approbation de cette demande de sortie personnelle ?',

2
lib/Views/commandManagement.dart

@ -480,7 +480,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
pw.SizedBox(height: 2), pw.SizedBox(height: 2),
pw.Text('ID: ${pointDeVente?['nom'] ?? 'S405A'}-${client?.id ?? 'Non spécifié'}', style: smallTextStyle), pw.Text('ID: ${pointDeVente?['nom'] ?? 'S405A'}-${client?.id ?? 'Non spécifié'}', style: smallTextStyle),
pw.Container(width: 100, height: 1, color: PdfColors.black, margin: const pw.EdgeInsets.symmetric(vertical: 2)), pw.Container(width: 100, height: 1, color: PdfColors.black, margin: const pw.EdgeInsets.symmetric(vertical: 2)),
pw.Text('${client?.nom} \n ${client?.prenom}', style: boldTextStyle), pw.Text('${client?.nom} ${client?.prenom}', style: boldTextStyle),
pw.SizedBox(height: 2), pw.SizedBox(height: 2),
pw.Text(client?.telephone ?? 'Non spécifié', style: tinyTextStyle), pw.Text(client?.telephone ?? 'Non spécifié', style: tinyTextStyle),
], ],

87
lib/Views/demande_sortie_personnelle_page.dart

@ -56,47 +56,44 @@ class _DemandeSortiePersonnellePageState
} }
void _scanQrOrBarcode() async { void _scanQrOrBarcode() async {
// Open the mobile scanner as a modal widget
await showDialog( await showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
return AlertDialog( return AlertDialog(
content: Container( content: Container(
width: double.maxFinite, width: double.maxFinite,
height: 400, // Adjust according to your needs height: 400,
child: MobileScanner( child: MobileScanner(
onDetect: (barcodeCapture) { onDetect: (BarcodeCapture barcodeCap) {
String scanResult = barcodeCapture.rawValue ?? ''; print("BarcodeCapture: $barcodeCap");
Navigator.of(context).pop(); // Close dialog after scanning // Now accessing the barcodes attribute
final List<Barcode> barcodes = barcodeCap.barcodes;
if (scanResult.isEmpty) return;
if (barcodes.isNotEmpty) {
setState(() { // Get the first detected barcode value
_searchController.text = scanResult; // Show scanned text String? scanResult = barcodes.first.rawValue;
});
print("Scanned Result: $scanResult");
// Assume IMEI is always 15 digits, adjust if necessary
Product? found; if (scanResult != null && scanResult.isNotEmpty) {
if (scanResult.length == 15 && setState(() {
int.tryParse(scanResult) != null) { _searchController.text = scanResult;
found = print(
_products.firstWhereOrNull((p) => p.imei == scanResult); "Updated Search Controller: ${_searchController.text}");
});
// Close dialog after scanning
Navigator.of(context).pop();
// Refresh product list based on new search input
_filterProducts();
} else {
print("Scan result was empty or null.");
Navigator.of(context).pop();
}
} else { } else {
found = _products print("No barcodes detected.");
.firstWhereOrNull((p) => p.reference == scanResult); Navigator.of(context).pop();
}
if (found != null) {
setState(() {
_selectedProduct = found;
_filteredProducts = [found!];
});
} else {
_showErrorSnackbar('Aucun produit trouvé avec ce code.');
setState(() {
_filteredProducts = [];
_selectedProduct = null;
});
} }
}, },
), ),
@ -127,13 +124,30 @@ class _DemandeSortiePersonnellePageState
try { try {
final products = await _database.getProducts(); final products = await _database.getProducts();
setState(() { setState(() {
_products = products.where((p) => (p.stock ?? 0) > 0).toList(); _products = products.where((p) {
// Check stock availability
print("point de vente id: ${_userController.pointDeVenteId}");
bool hasStock = _userController.pointDeVenteId == 0
? (p.stock ?? 0) > 0
: (p.stock ?? 0) > 0 &&
p.pointDeVenteId == _userController.pointDeVenteId;
return hasStock;
}).toList();
// Setting filtered products
_filteredProducts = _products; _filteredProducts = _products;
// End loading state
_isLoading = false; _isLoading = false;
}); });
// Start the animation
_animationController.forward(); _animationController.forward();
} catch (e) { } catch (e) {
setState(() => _isLoading = false); // Handle any errors
setState(() {
_isLoading = false;
});
_showErrorSnackbar('Impossible de charger les produits: $e'); _showErrorSnackbar('Impossible de charger les produits: $e');
} }
} }
@ -403,6 +417,9 @@ class _DemandeSortiePersonnellePageState
hintText: 'Rechercher un produit...', hintText: 'Rechercher un produit...',
prefixIcon: Icon(Icons.search, color: Colors.grey.shade600), prefixIcon: Icon(Icons.search, color: Colors.grey.shade600),
), ),
onChanged: (value) {
_filterProducts(); // Call to filter products
},
), ),
), ),
IconButton( IconButton(

44
lib/Views/historique.dart

@ -5,7 +5,7 @@
import 'package:youmazgestion/Components/appDrawer.dart'; import 'package:youmazgestion/Components/appDrawer.dart';
import 'package:youmazgestion/Models/client.dart'; import 'package:youmazgestion/Models/client.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart'; import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import 'package:youmazgestion/controller/userController.dart';
class HistoriquePage extends StatefulWidget { class HistoriquePage extends StatefulWidget {
const HistoriquePage({super.key}); const HistoriquePage({super.key});
@ -20,6 +20,10 @@
final List<Commande> _commandes = []; final List<Commande> _commandes = [];
final List<Commande> _filteredCommandes = []; final List<Commande> _filteredCommandes = [];
List<Map<String, dynamic>> _pointsDeVente = [];
String? _selectedPointDeVente;
final UserController _userController = Get.find<UserController>();
bool _isLoading = true; bool _isLoading = true;
DateTimeRange? _dateRange; DateTimeRange? _dateRange;
@ -38,6 +42,7 @@
void initState() { void initState() {
super.initState(); super.initState();
_loadCommandes(); _loadCommandes();
_loadPointsDeVenteWithDefault();
// Listeners pour les filtres // Listeners pour les filtres
_searchController.addListener(_filterCommandes); _searchController.addListener(_filterCommandes);
@ -45,6 +50,37 @@
_searchCommandeIdController.addListener(_filterCommandes); _searchCommandeIdController.addListener(_filterCommandes);
} }
Future<void> _loadPointsDeVenteWithDefault() async {
try {
print(_userController.userId);
final points = await _appDatabase.getPointsDeVente();
setState(() {
_pointsDeVente = points;
if (points.isNotEmpty) {
if (_userController.pointDeVenteId > 0) {
final userPointDeVente = points.firstWhere(
(point) => point['id'] == _userController.pointDeVenteId,
orElse: () => <String, dynamic>{},
);
if (userPointDeVente.isNotEmpty) {
_selectedPointDeVente = userPointDeVente['nom'] as String;
} else {
_selectedPointDeVente = points[0]['nom'] as String;
}
} else {
_selectedPointDeVente = points[0]['nom'] as String;
}
}
});
} catch (e) {
Get.snackbar('Erreur', 'Impossible de charger les points de vente: $e');
print('❌ Erreur chargement points de vente: $e');
}
}
Future<void> _loadCommandes() async { Future<void> _loadCommandes() async {
setState(() { setState(() {
_isLoading = true; _isLoading = true;
@ -52,6 +88,7 @@
try { try {
final commandes = await _appDatabase.getCommandes(); final commandes = await _appDatabase.getCommandes();
setState(() { setState(() {
_commandes.clear(); _commandes.clear();
_commandes.addAll(commandes); _commandes.addAll(commandes);
@ -498,6 +535,7 @@
children: [ children: [
_buildDetailRow('Client', '${client?.nom} ${client?.prenom}', Icons.person), _buildDetailRow('Client', '${client?.nom} ${client?.prenom}', Icons.person),
_buildDetailRow('Date', DateFormat('dd/MM/yyyy à HH:mm').format(commande.dateCommande), Icons.calendar_today), _buildDetailRow('Date', DateFormat('dd/MM/yyyy à HH:mm').format(commande.dateCommande), Icons.calendar_today),
_buildDetailRow('Client', '${_selectedPointDeVente} ', Icons.person),
Row( Row(
children: [ children: [
Icon(Icons.assignment, size: 16, color: Colors.grey.shade600), Icon(Icons.assignment, size: 16, color: Colors.grey.shade600),
@ -729,6 +767,8 @@
// Widget pour l'item de commande (adapté pour mobile) // Widget pour l'item de commande (adapté pour mobile)
Widget _buildCommandeListItem(Commande commande) { Widget _buildCommandeListItem(Commande commande) {
final isMobile = MediaQuery.of(context).size.width < 600; final isMobile = MediaQuery.of(context).size.width < 600;
// print(commande.commandeurId);
print(_userController.userId);
return Card( return Card(
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
@ -777,7 +817,7 @@
), ),
), ),
Text( Text(
'${commande.clientNom} ${commande.clientPrenom}', '${_selectedPointDeVente}',
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
fontSize: 14, fontSize: 14,

2
lib/config/DatabaseConfig.dart

@ -80,7 +80,7 @@ class DatabaseConfig {
config['database']?.toString().isNotEmpty == true && config['database']?.toString().isNotEmpty == true &&
config['user'] != null; config['user'] != null;
} catch (e) { } catch (e) {
print("Erreur de validation de la configuration: $e"); // print("Erreur de validation de la configuration: $e");
return false; return false;
} }
} }

31
lib/controller/HistoryController.dart

@ -27,8 +27,6 @@ class HistoryController extends GetxController {
getTotalSumOrdersByMonth(DateTime.now()); getTotalSumOrdersByMonth(DateTime.now());
getOrdersByMonth(DateTime.now()); getOrdersByMonth(DateTime.now());
getOrderCountByMonth(DateTime.now()); getOrderCountByMonth(DateTime.now());
} }
Future<void> fetchOrders() async { Future<void> fetchOrders() async {
@ -60,9 +58,6 @@ class HistoryController extends GetxController {
} }
} }
List<DateTime?> getDistinctDates() { List<DateTime?> getDistinctDates() {
final currentDate = DateTime.now(); final currentDate = DateTime.now();
final dates = [...orders.map((order) => order.startDate), currentDate] final dates = [...orders.map((order) => order.startDate), currentDate]
@ -73,7 +68,9 @@ class HistoryController extends GetxController {
List<Order> filterOrdersByDateRange(DateTime startDate) { List<Order> filterOrdersByDateRange(DateTime startDate) {
final filteredList = orders final filteredList = orders
.where((order) => order.startDate != null && order.startDate!.isAtSameMomentAs(startDate)) .where((order) =>
order.startDate != null &&
order.startDate!.isAtSameMomentAs(startDate))
.toList(); .toList();
filteredOrders.value = filteredList; filteredOrders.value = filteredList;
return filteredList; return filteredList;
@ -81,7 +78,8 @@ class HistoryController extends GetxController {
Future<List<Order>> getOrdersByStartDate(DateTime startDate) async { Future<List<Order>> getOrdersByStartDate(DateTime startDate) async {
try { try {
final ordersByStartDate = await _orderDatabase.getOrdersByStartDate(startDate); final ordersByStartDate =
await _orderDatabase.getOrdersByStartDate(startDate);
return ordersByStartDate; return ordersByStartDate;
} catch (e) { } catch (e) {
print(e); print(e);
@ -89,22 +87,23 @@ class HistoryController extends GetxController {
} }
} }
double getTotalSumOrdersByStartDate (DateTime startDate) { double getTotalSumOrdersByStartDate(DateTime startDate) {
final filteredOrders = filterOrdersByDateRange(startDate); final filteredOrders = filterOrdersByDateRange(startDate);
double totalSum = filteredOrders.fold(0, (sum, order) => sum + order.totalPrice); double totalSum =
filteredOrders.fold(0, (sum, order) => sum + order.totalPrice);
return totalSum; return totalSum;
} }
Future<RxDouble> getTotalSumOrdersByMonth(DateTime date) async { Future<RxDouble> getTotalSumOrdersByMonth(DateTime date) async {
final filteredOrders = await getOrdersByMonth(date); final filteredOrders = await getOrdersByMonth(date);
double totalsum = filteredOrders.fold(0, (sum, order) => sum + order.totalPrice); double totalsum =
filteredOrders.fold(0, (sum, order) => sum + order.totalPrice);
totalSum.value = totalsum; totalSum.value = totalsum;
print(totalSum.value); // print(totalSum.value);
return totalSum; return totalSum;
} }
Future<Map<String, int>> getProductQuantitiesByDate(DateTime date) async { Future<Map<String, int>> getProductQuantitiesByDate(DateTime date) async {
try { try {
return await _orderDatabase.getProductQuantitiesByDate(date); return await _orderDatabase.getProductQuantitiesByDate(date);
} catch (e) { } catch (e) {
@ -153,16 +152,10 @@ class HistoryController extends GetxController {
} }
} }
Future<int> getOrderCountByMonth(DateTime month) async { Future<int> getOrderCountByMonth(DateTime month) async {
List<Order> orders = await getOrdersByMonth(month); List<Order> orders = await getOrdersByMonth(month);
int orderCount = orders.length; int orderCount = orders.length;
orderQuantity.value = orderCount; orderQuantity.value = orderCount;
return orderCount; return orderCount;
} }
} }

14
lib/controller/userController.dart

@ -69,7 +69,7 @@ class UserController extends GetxController {
// Précharger les permissions en arrière-plan (non bloquant) // Précharger les permissions en arrière-plan (non bloquant)
_preloadPermissionsInBackground(); _preloadPermissionsInBackground();
} catch (dbError) { } catch (dbError) {
print("❌ Erreur BDD, utilisation du fallback: $dbError"); // print("❌ Erreur BDD, utilisation du fallback: $dbError");
_username.value = storedUsername; _username.value = storedUsername;
_email.value = prefs.getString('email') ?? ''; _email.value = prefs.getString('email') ?? '';
_role.value = storedRole; _role.value = storedRole;
@ -84,7 +84,7 @@ class UserController extends GetxController {
} }
} }
} catch (e) { } catch (e) {
print('❌ Erreur lors du chargement des données utilisateur: $e'); // print('❌ Erreur lors du chargement des données utilisateur: $e');
} }
} }
@ -129,10 +129,10 @@ class UserController extends GetxController {
_userId.value = userId; _userId.value = userId;
_pointDeVenteId.value = user.pointDeVenteId ?? 0; _pointDeVenteId.value = user.pointDeVenteId ?? 0;
print("✅ Utilisateur mis à jour avec credentials:"); // print("✅ Utilisateur mis à jour avec credentials:");
print(" Username: ${_username.value}"); // print(" Username: ${_username.value}");
print(" Role: ${_role.value}"); // print(" Role: ${_role.value}");
print(" UserID: ${_userId.value}"); // print(" UserID: ${_userId.value}");
saveUserData(); saveUserData();
@ -166,7 +166,7 @@ class UserController extends GetxController {
await prefs.setString( await prefs.setString(
'point_de_vente_designation', _pointDeVenteDesignation.value); 'point_de_vente_designation', _pointDeVenteDesignation.value);
print("✅ Données sauvegardées avec succès"); // print("✅ Données sauvegardées avec succès");
} catch (e) { } catch (e) {
print('❌ Erreur lors de la sauvegarde: $e'); print('❌ Erreur lors de la sauvegarde: $e');
} }

24
lib/main.dart

@ -9,34 +9,34 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
try { try {
print("Initialisation de l'application..."); // print("Initialisation de l'application...");
// Pour le développement : supprimer toutes les tables (équivalent à deleteDatabaseFile) // // Pour le développement : supprimer toutes les tables (équivalent à deleteDatabaseFile)
// ATTENTION: Décommentez seulement si vous voulez réinitialiser la base // // ATTENTION: Décommentez seulement si vous voulez réinitialiser la base
// await AppDatabase.instance.deleteDatabaseFile(); // // await AppDatabase.instance.deleteDatabaseFile();
// Initialiser la base de données MySQL // // Initialiser la base de données MySQL
print("Connexion à la base de données MySQL..."); // print("Connexion à la base de données MySQL...");
// await AppDatabase.instance.initDatabase(); // // await AppDatabase.instance.initDatabase();
print("Base de données initialisée avec succès !"); // print("Base de données initialisée avec succès !");
// Afficher les informations de la base (pour debug) // Afficher les informations de la base (pour debug)
await AppDatabase.instance.printDatabaseInfo(); await AppDatabase.instance.printDatabaseInfo();
// Initialiser le contrôleur utilisateur // Initialiser le contrôleur utilisateur
Get.put(UserController()); Get.put(UserController());
print("Contrôleur utilisateur initialisé"); // print("Contrôleur utilisateur initialisé");
// Configurer le logger // Configurer le logger
setupLogger(); setupLogger();
print("Lancement de l'application..."); // print("Lancement de l'application...");
runApp(const GetMaterialApp( runApp(const GetMaterialApp(
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
home: MyApp(), home: MyApp(),
)); ));
} catch (e) { } catch (e) {
print('Erreur lors de l\'initialisation: $e'); // print('Erreur lors de l\'initialisation: $e');
// Afficher une page d'erreur avec plus de détails // Afficher une page d'erreur avec plus de détails
runApp(MaterialApp( runApp(MaterialApp(
@ -129,6 +129,6 @@ void main() async {
void setupLogger() { void setupLogger() {
Logger.root.level = Level.ALL; Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((record) { Logger.root.onRecord.listen((record) {
print('${record.level.name}: ${record.time}: ${record.message}'); // print('${record.level.name}: ${record.time}: ${record.message}');
}); });
} }
Loading…
Cancel
Save