Compare commits

..

7 Commits

Author SHA1 Message Date
25abc65480 couleur page de login 2025-05-31 00:45:16 +03:00
beb2048a7a boutton scan qr 2025-05-31 00:17:19 +03:00
b1d176aa2a add card on the list 2025-05-30 23:48:07 +03:00
8d86d99e24 pointage de base 2025-05-30 23:42:39 +03:00
5f665acf35 Change DA to MGA 2025-05-30 22:38:17 +03:00
38af810b79 Change DA to MGA 2025-05-30 22:36:29 +03:00
da03076411 Change DA to MGA 2025-05-30 22:31:20 +03:00
43 changed files with 3020 additions and 9737 deletions

View File

@ -1,6 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<application <application
android:label="my_app" android:label="my_app"
android:name="${applicationName}" android:name="${applicationName}"
@ -14,7 +12,6 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues while the Flutter UI initializes. After that, this theme continues

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -2,8 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSCameraUsageDescription</key>
<string>Cette application a besoin d'accéder à la caméra pour scanner les codes QR</string>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
@ -49,6 +47,5 @@
<true/> <true/>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
</dict> </dict>
</plist> </plist>

View File

@ -1,259 +0,0 @@
import 'dart:io';
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
class ScanQRPage extends StatefulWidget {
const ScanQRPage({super.key});
@override
State<ScanQRPage> createState() => _ScanQRPageState();
}
class _ScanQRPageState extends State<ScanQRPage> {
MobileScannerController? cameraController;
bool _isScanComplete = false;
String? _scannedData;
bool _hasError = false;
String? _errorMessage;
bool get isMobile => !kIsWeb && (Platform.isAndroid || Platform.isIOS);
@override
void initState() {
super.initState();
_initializeController();
}
void _initializeController() {
if (!isMobile) {
setState(() {
_hasError = true;
_errorMessage = "Le scanner QR n'est pas disponible sur cette plateforme.";
});
return;
}
try {
cameraController = MobileScannerController(
detectionSpeed: DetectionSpeed.noDuplicates,
facing: CameraFacing.back,
torchEnabled: false,
);
setState(() {
_hasError = false;
_errorMessage = null;
});
} catch (e) {
setState(() {
_hasError = true;
_errorMessage = 'Erreur d\'initialisation de la caméra: $e';
});
}
}
@override
void dispose() {
cameraController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Scanner QR Code'),
actions: _hasError ? [] : [
if (cameraController != null) ...[
IconButton(
color: Colors.white,
icon: const Icon(Icons.flash_on, color: Colors.white),
iconSize: 32.0,
onPressed: () => cameraController!.toggleTorch(),
),
IconButton(
color: Colors.white,
icon: const Icon(Icons.flip_camera_ios, color: Colors.white),
iconSize: 32.0,
onPressed: () => cameraController!.switchCamera(),
),
],
],
),
body: _hasError ? _buildErrorWidget() : _buildScannerWidget(),
);
}
Widget _buildErrorWidget() {
return Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.error_outline,
size: 64,
color: Colors.red,
),
const SizedBox(height: 16),
const Text(
'Erreur de caméra',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
_errorMessage ?? 'Une erreur s\'est produite',
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
_initializeController();
},
child: const Text('Réessayer'),
),
const SizedBox(height: 16),
const Text(
'Vérifiez que:\n• Le plugin mobile_scanner est installé\n• Les permissions de caméra sont accordées\n• Votre appareil a une caméra fonctionnelle',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 14, color: Colors.grey),
),
],
),
),
);
}
Widget _buildScannerWidget() {
if (cameraController == null) {
return const Center(child: CircularProgressIndicator());
}
return Stack(
children: [
MobileScanner(
controller: cameraController!,
onDetect: (capture) {
final List<Barcode> barcodes = capture.barcodes;
for (final barcode in barcodes) {
if (!_isScanComplete && barcode.rawValue != null) {
_isScanComplete = true;
_scannedData = barcode.rawValue;
_showScanResult(context, _scannedData!);
}
}
},
errorBuilder: (context, error, child) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error, size: 64, color: Colors.red),
const SizedBox(height: 16),
Text('Erreur: ${error.errorDetails?.message ?? 'Erreur inconnue'}'),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () => _initializeController(),
child: const Text('Réessayer'),
),
],
),
);
},
),
CustomPaint(
painter: QrScannerOverlay(
borderColor: Colors.blue.shade800,
),
),
],
);
}
void _showScanResult(BuildContext context, String data) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Résultat du scan'),
content: SelectableText(data), // Permet de sélectionner le texte
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
setState(() {
_isScanComplete = false;
});
},
child: const Text('Fermer'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
Navigator.pop(context, data); // Retourner la donnée scannée
},
child: const Text('Utiliser'),
),
],
),
).then((_) {
setState(() {
_isScanComplete = false;
});
});
}
}
class QrScannerOverlay extends CustomPainter {
final Color borderColor;
QrScannerOverlay({required this.borderColor});
@override
void paint(Canvas canvas, Size size) {
final double width = size.width;
final double height = size.height;
final double borderWidth = 2.0;
final double borderLength = 30.0;
final double areaSize = width * 0.7;
final Paint backgroundPaint = Paint()
..color = Colors.black.withOpacity(0.4);
canvas.drawRect(Rect.fromLTRB(0, 0, width, height), backgroundPaint);
final Paint transparentPaint = Paint()
..color = Colors.transparent
..blendMode = BlendMode.clear;
final double areaLeft = (width - areaSize) / 2;
final double areaTop = (height - areaSize) / 2;
canvas.drawRect(
Rect.fromLTRB(areaLeft, areaTop, areaLeft + areaSize, areaTop + areaSize),
transparentPaint,
);
final Paint borderPaint = Paint()
..color = borderColor
..strokeWidth = borderWidth
..style = PaintingStyle.stroke;
// Coins du scanner
_drawCorner(canvas, borderPaint, areaLeft, areaTop, borderLength, true, true);
_drawCorner(canvas, borderPaint, areaLeft + areaSize, areaTop, borderLength, false, true);
_drawCorner(canvas, borderPaint, areaLeft, areaTop + areaSize, borderLength, true, false);
_drawCorner(canvas, borderPaint, areaLeft + areaSize, areaTop + areaSize, borderLength, false, false);
}
void _drawCorner(Canvas canvas, Paint paint, double x, double y, double length, bool isLeft, bool isTop) {
final double horizontalStart = isLeft ? x : x - length;
final double horizontalEnd = isLeft ? x + length : x;
final double verticalStart = isTop ? y : y - length;
final double verticalEnd = isTop ? y + length : y;
canvas.drawLine(Offset(horizontalStart, y), Offset(horizontalEnd, y), paint);
canvas.drawLine(Offset(x, verticalStart), Offset(x, verticalEnd), paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:youmazgestion/Views/Dashboard.dart';
import 'package:youmazgestion/Views/HandleProduct.dart'; import 'package:youmazgestion/Views/HandleProduct.dart';
import 'package:youmazgestion/Views/RoleListPage.dart'; import 'package:youmazgestion/Views/RoleListPage.dart';
import 'package:youmazgestion/Views/commandManagement.dart'; import 'package:youmazgestion/Views/commandManagement.dart';
@ -106,7 +105,7 @@ class CustomDrawer extends StatelessWidget {
color: Colors.blue, color: Colors.blue,
permissionAction: 'view', permissionAction: 'view',
permissionRoute: '/accueil', permissionRoute: '/accueil',
onTap: () => Get.to( DashboardPage()), onTap: () => Get.to(const AccueilPage()),
), ),
); );
@ -229,11 +228,11 @@ class CustomDrawer extends StatelessWidget {
List<Widget> rapportsItems = [ List<Widget> rapportsItems = [
await _buildDrawerItem( await _buildDrawerItem(
icon: Icons.bar_chart, icon: Icons.bar_chart,
title: "Bilan ", title: "Bilan mensuel",
color: Colors.teal, color: Colors.teal,
permissionAction: 'read', permissionAction: 'read',
permissionRoute: '/bilan', permissionRoute: '/bilan',
onTap: () => Get.to( DashboardPage()), onTap: () => Get.to(const BilanMois()),
), ),
await _buildDrawerItem( await _buildDrawerItem(
icon: Icons.history, icon: Icons.history,
@ -292,129 +291,31 @@ class CustomDrawer extends StatelessWidget {
drawerItems.add(const Divider()); drawerItems.add(const Divider());
drawerItems.add( drawerItems.add(
ListTile( ListTile(
leading: const Icon(Icons.logout, color: Colors.red), leading: const Icon(Icons.logout, color: Colors.red),
title: const Text("Déconnexion"), title: const Text("Déconnexion"),
onTap: () { onTap: () {
Get.dialog( Get.defaultDialog(
AlertDialog( title: "Déconnexion",
shape: RoundedRectangleBorder( content: const Text("Voulez-vous vraiment vous déconnecter ?"),
borderRadius: BorderRadius.circular(16), actions: [
), TextButton(
contentPadding: EdgeInsets.zero, child: const Text("Non"),
content: Container( onPressed: () => Get.back(),
constraints: const BoxConstraints(maxWidth: 400), ),
child: Column( ElevatedButton(
mainAxisSize: MainAxisSize.min, style: ElevatedButton.styleFrom(
children: [ backgroundColor: Colors.red,
// Header
Container(
width: double.infinity,
padding: const EdgeInsets.all(24),
child: Column(
children: [
Icon(
Icons.logout_rounded,
size: 48,
color: Colors.orange.shade600,
), ),
const SizedBox(height: 16), child: const Text("Oui"),
const Text( onPressed: () async {
"Déconnexion", await clearUserData();
style: TextStyle( Get.offAll(const LoginPage());
fontSize: 20, },
fontWeight: FontWeight.w600, ),
color: Colors.black87, ],
), );
),
const SizedBox(height: 12),
const Text(
"Êtes-vous sûr de vouloir vous déconnecter ?",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Colors.black87,
height: 1.4,
),
),
const SizedBox(height: 8),
Text(
"Vous devrez vous reconnecter pour accéder à votre compte.",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: Colors.grey.shade600,
height: 1.3,
),
),
],
),
),
// Actions
Container(
width: double.infinity,
padding: const EdgeInsets.fromLTRB(24, 0, 24, 24),
child: Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => Get.back(),
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
side: BorderSide(
color: Colors.grey.shade300,
width: 1.5,
),
),
child: const Text(
"Annuler",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: () async {
await clearUserData();
Get.offAll(const LoginPage());
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red.shade600,
foregroundColor: Colors.white,
elevation: 2,
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text(
"Se déconnecter",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
],
),
),
],
),
),
),
barrierDismissible: true,
);
}, },
), ),
); );
@ -448,6 +349,3 @@ class CustomDrawer extends StatelessWidget {
); );
} }
} }
class HistoryPage {
}

View File

@ -1,121 +1,31 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:youmazgestion/controller/userController.dart';
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
final String title; final String title;
final Widget? subtitle; final Widget? subtitle;
final List<Widget>? actions;
final bool automaticallyImplyLeading;
final Color? backgroundColor;
final bool isDesktop; // Add this parameter
final UserController userController = Get.put(UserController()); const CustomAppBar({
CustomAppBar({
Key? key, Key? key,
required this.title, required this.title,
this.subtitle, this.subtitle,
this.actions,
this.automaticallyImplyLeading = true,
this.backgroundColor,
this.isDesktop = false, // Add this parameter with default value
}) : super(key: key); }) : super(key: key);
@override @override
Size get preferredSize => Size.fromHeight(subtitle == null ? 56.0 : 80.0); Size get preferredSize => Size.fromHeight(subtitle == null ? 56.0 : 72.0);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return AppBar(
decoration: BoxDecoration( title: subtitle == null
gradient: LinearGradient( ? Text(title)
begin: Alignment.topLeft, : Column(
end: Alignment.bottomRight, crossAxisAlignment: CrossAxisAlignment.start,
colors: [ children: [
Colors.blue.shade900, Text(title, style: TextStyle(fontSize: 20)),
Colors.blue.shade800, subtitle!,
],
),
boxShadow: [
BoxShadow(
color: Colors.blue.shade900.withOpacity(0.3),
offset: const Offset(0, 2),
blurRadius: 4,
),
],
),
child: AppBar(
backgroundColor: backgroundColor ?? Colors.transparent,
elevation: 0,
automaticallyImplyLeading: automaticallyImplyLeading,
centerTitle: false,
iconTheme: const IconThemeData(
color: Colors.white,
size: 24,
),
actions: actions,
title: subtitle == null
? Text(
title,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.white,
letterSpacing: 0.5,
),
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
title,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.white,
letterSpacing: 0.5,
),
),
const SizedBox(height: 2),
Obx(() => Text(
userController.role != 'Super Admin'
? 'Point de vente: ${userController.pointDeVenteDesignation}'
: '',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w400,
color: Colors.white.withOpacity(0.9),
letterSpacing: 0.3,
),
)),
if (subtitle != null) ...[
const SizedBox(height: 2),
DefaultTextStyle(
style: TextStyle(
fontSize: 12,
color: Colors.white.withOpacity(0.8),
fontWeight: FontWeight.w400,
),
child: subtitle!,
),
],
],
),
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.blue.shade900,
Colors.blue.shade800,
], ],
), ),
), // autres propriétés si besoin
),
),
); );
} }
} }

View File

@ -1,7 +0,0 @@
enum PaymentType {
cash,
card,
mvola,
orange,
airtel
}

View File

@ -49,9 +49,13 @@ class Client {
String get nomComplet => '$prenom $nom'; String get nomComplet => '$prenom $nom';
} }
// Models/commande.dart
enum StatutCommande { enum StatutCommande {
enAttente, enAttente,
confirmee, confirmee,
enPreparation,
expediee,
livree,
annulee annulee
} }
@ -63,8 +67,6 @@ class Commande {
final double montantTotal; final double montantTotal;
final String? notes; final String? notes;
final DateTime? dateLivraison; final DateTime? dateLivraison;
final int? commandeurId;
final int? validateurId;
// Données du client (pour les jointures) // Données du client (pour les jointures)
final String? clientNom; final String? clientNom;
@ -79,8 +81,6 @@ class Commande {
required this.montantTotal, required this.montantTotal,
this.notes, this.notes,
this.dateLivraison, this.dateLivraison,
this.commandeurId,
this.validateurId,
this.clientNom, this.clientNom,
this.clientPrenom, this.clientPrenom,
this.clientEmail, this.clientEmail,
@ -95,8 +95,6 @@ class Commande {
'montantTotal': montantTotal, 'montantTotal': montantTotal,
'notes': notes, 'notes': notes,
'dateLivraison': dateLivraison?.toIso8601String(), 'dateLivraison': dateLivraison?.toIso8601String(),
'commandeurId': commandeurId,
'validateurId': validateurId,
}; };
} }
@ -111,8 +109,6 @@ class Commande {
dateLivraison: map['dateLivraison'] != null dateLivraison: map['dateLivraison'] != null
? DateTime.parse(map['dateLivraison']) ? DateTime.parse(map['dateLivraison'])
: null, : null,
commandeurId: map['commandeurId'],
validateurId: map['validateurId'],
clientNom: map['clientNom'], clientNom: map['clientNom'],
clientPrenom: map['clientPrenom'], clientPrenom: map['clientPrenom'],
clientEmail: map['clientEmail'], clientEmail: map['clientEmail'],
@ -125,16 +121,14 @@ class Commande {
return 'En attente'; return 'En attente';
case StatutCommande.confirmee: case StatutCommande.confirmee:
return 'Confirmée'; return 'Confirmée';
// case StatutCommande.enPreparation: case StatutCommande.enPreparation:
// return 'En préparation'; return 'En préparation';
// case StatutCommande.expediee: case StatutCommande.expediee:
// return 'Expédiée'; return 'Expédiée';
// case StatutCommande.livree: case StatutCommande.livree:
// return 'Livrée'; return 'Livrée';
case StatutCommande.annulee: case StatutCommande.annulee:
return 'Annulée'; return 'Annulée';
default:
return 'Inconnu';
} }
} }
@ -144,7 +138,6 @@ class Commande {
: 'Client inconnu'; : 'Client inconnu';
} }
// Models/detail_commande.dart // Models/detail_commande.dart
class DetailCommande { class DetailCommande {
final int? id; final int? id;

View File

@ -1,18 +1,13 @@
class Product { class Product {
final int? id; int? id;
final String name; final String name;
final double price; final double price;
final String? image; final String? image;
final String category; final String category;
final int stock; final int? stock;
final String? description; final String? description;
String? qrCode; String? qrCode;
final String? reference; final String? reference;
final int? pointDeVenteId;
final String? marque;
final String? ram;
final String? memoireInterne;
final String? imei;
Product({ Product({
this.id, this.id,
@ -21,16 +16,11 @@ class Product {
this.image, this.image,
required this.category, required this.category,
this.stock = 0, this.stock = 0,
this.description, this.description = '',
this.qrCode, this.qrCode,
this.reference, this.reference,
this.pointDeVenteId,
this.marque,
this.ram,
this.memoireInterne,
this.imei,
}); });
// Vérifie si le stock est défini
bool isStockDefined() { bool isStockDefined() {
if (stock != null) { if (stock != null) {
print("stock is defined : $stock $name"); print("stock is defined : $stock $name");
@ -39,37 +29,31 @@ class Product {
return false; return false;
} }
} }
factory Product.fromMap(Map<String, dynamic> map) => Product( Map<String, dynamic> toMap() {
id: map['id'], return {
name: map['name'], 'id': id,
price: map['price'], 'name': name,
image: map['image'], 'price': price,
category: map['category'], 'image': image ?? '',
stock: map['stock'], 'category': category,
description: map['description'], 'stock': stock ?? 0,
qrCode: map['qrCode'], 'description': description ?? '',
reference: map['reference'], 'qrCode': qrCode ?? '',
pointDeVenteId: map['point_de_vente_id'], 'reference': reference ?? '',
marque: map['marque'], };
ram: map['ram'], }
memoireInterne: map['memoire_interne'],
imei: map['imei'],
);
Map<String, dynamic> toMap() => { factory Product.fromMap(Map<String, dynamic> map) {
'id': id, return Product(
'name': name, id: map['id'],
'price': price, name: map['name'],
'image': image, price: map['price'],
'category': category, image: map['image'],
'stock': stock, category: map['category'],
'description': description, stock: map['stock'],
'qrCode': qrCode, description: map['description'],
'reference': reference, qrCode: map['qrCode'],
'point_de_vente_id': pointDeVenteId, reference: map['reference'],
'marque': marque, );
'ram': ram, }
'memoire_interne': memoireInterne,
'imei': imei,
};
} }

View File

@ -7,7 +7,6 @@ class Users {
String username; String username;
int roleId; int roleId;
String? roleName; // Optionnel, rempli lors des requêtes avec JOIN String? roleName; // Optionnel, rempli lors des requêtes avec JOIN
int? pointDeVenteId;
Users({ Users({
this.id, this.id,
@ -18,7 +17,6 @@ class Users {
required this.username, required this.username,
required this.roleId, required this.roleId,
this.roleName, this.roleName,
this.pointDeVenteId,
}); });
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
@ -29,7 +27,6 @@ class Users {
'password': password, 'password': password,
'username': username, 'username': username,
'role_id': roleId, 'role_id': roleId,
'point_de_vente_id' : pointDeVenteId,
}; };
} }
@ -49,11 +46,9 @@ class Users {
username: map['username'], username: map['username'],
roleId: map['role_id'], roleId: map['role_id'],
roleName: map['role_name'], // Depuis les requêtes avec JOIN roleName: map['role_name'], // Depuis les requêtes avec JOIN
pointDeVenteId : map['point_de_vente_id']
); );
} }
// Getter pour la compatibilité avec l'ancien code // Getter pour la compatibilité avec l'ancien code
String get role => roleName ?? ''; String get role => roleName ?? '';
} }

View File

@ -0,0 +1,728 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import '../Models/users.dart';
import '../Models/role.dart';
import '../Models/Permission.dart';
class AppDatabase {
static final AppDatabase instance = AppDatabase._init();
late Database _database;
AppDatabase._init() {
sqfliteFfiInit();
}
Future<Database> get database async {
if (_database.isOpen) return _database;
_database = await _initDB('app_database.db');
return _database;
}
Future<void> initDatabase() async {
_database = await _initDB('app_database.db');
await _createDB(_database, 1);
await insertDefaultPermissions();
await insertDefaultMenus();
await insertDefaultRoles();
await insertDefaultSuperAdmin();
}
Future<Database> _initDB(String filePath) async {
final documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, filePath);
bool dbExists = await File(path).exists();
if (!dbExists) {
try {
ByteData data = await rootBundle.load('assets/database/$filePath');
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
await File(path).writeAsBytes(bytes);
} catch (e) {
print('Pas de fichier DB dans assets, création d\'une nouvelle DB');
}
}
return await databaseFactoryFfi.openDatabase(path);
}
Future<void> _createDB(Database db, int version) async {
final tables =
await db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'");
final tableNames = tables.map((row) => row['name'] as String).toList();
if (!tableNames.contains('roles')) {
await db.execute('''
CREATE TABLE roles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
designation TEXT NOT NULL UNIQUE
)
''');
print("Table 'roles' créée.");
}
if (!tableNames.contains('permissions')) {
await db.execute('''
CREATE TABLE permissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE
)
''');
print("Table 'permissions' créée.");
}
if (!tableNames.contains('menu')) {
await db.execute('''
CREATE TABLE menu (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
route TEXT NOT NULL UNIQUE
)
''');
print("Table 'menu' créée.");
}
if (!tableNames.contains('role_permissions')) {
await db.execute('''
CREATE TABLE role_permissions (
role_id INTEGER,
permission_id INTEGER,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
)
''');
print("Table 'role_permissions' créée.");
}
if (!tableNames.contains('menu_permissions')) {
await db.execute('''
CREATE TABLE menu_permissions (
menu_id INTEGER,
permission_id INTEGER,
PRIMARY KEY (menu_id, permission_id),
FOREIGN KEY (menu_id) REFERENCES menu(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
)
''');
print("Table 'menu_permissions' créée.");
}
if (!tableNames.contains('users')) {
await db.execute('''
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
lastname TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
password TEXT NOT NULL,
username TEXT NOT NULL UNIQUE,
role_id INTEGER NOT NULL,
FOREIGN KEY (role_id) REFERENCES roles(id)
)
''');
print("Table 'users' créée.");
}
if (!tableNames.contains('role_menu_permissions')) {
await db.execute('''
CREATE TABLE role_menu_permissions (
role_id INTEGER,
menu_id INTEGER,
permission_id INTEGER,
PRIMARY KEY (role_id, menu_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (menu_id) REFERENCES menu(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
)
''');
print("Table 'role_menu_permissions' créée.");
}
}
Future<void> insertDefaultPermissions() async {
final db = await database;
final existing = await db.query('permissions');
if (existing.isEmpty) {
await db.insert('permissions', {'name': 'view'});
await db.insert('permissions', {'name': 'create'});
await db.insert('permissions', {'name': 'update'});
await db.insert('permissions', {'name': 'delete'});
await db.insert('permissions', {'name': 'admin'});
await db.insert('permissions', {'name': 'manage'}); // Nouvelle permission
await db.insert('permissions', {'name': 'read'}); // Nouvelle permission
print("Permissions par défaut insérées");
} else {
// Vérifier et ajouter les nouvelles permissions si elles n'existent pas
final newPermissions = ['manage', 'read'];
for (var permission in newPermissions) {
final existingPermission = await db
.query('permissions', where: 'name = ?', whereArgs: [permission]);
if (existingPermission.isEmpty) {
await db.insert('permissions', {'name': permission});
print("Permission ajoutée: $permission");
}
}
}
}
Future<void> insertDefaultMenus() async {
final db = await database;
final existingMenus = await db.query('menu');
if (existingMenus.isEmpty) {
// Menus existants
await db.insert('menu', {'name': 'Accueil', 'route': '/accueil'});
await db.insert('menu',
{'name': 'Ajouter un utilisateur', 'route': '/ajouter-utilisateur'});
await db.insert('menu', {
'name': 'Modifier/Supprimer un utilisateur',
'route': '/modifier-utilisateur'
});
await db.insert(
'menu', {'name': 'Ajouter un produit', 'route': '/ajouter-produit'});
await db.insert('menu', {
'name': 'Modifier/Supprimer un produit',
'route': '/modifier-produit'
});
await db.insert('menu', {'name': 'Bilan', 'route': '/bilan'});
await db
.insert('menu', {'name': 'Gérer les rôles', 'route': '/gerer-roles'});
await db.insert(
'menu', {'name': 'Gestion de stock', 'route': '/gestion-stock'});
await db.insert('menu', {'name': 'Historique', 'route': '/historique'});
await db.insert('menu', {'name': 'Déconnexion', 'route': '/deconnexion'});
// Nouveaux menus ajoutés
await db.insert(
'menu', {'name': 'Nouvelle commande', 'route': '/nouvelle-commande'});
await db.insert(
'menu', {'name': 'Gérer les commandes', 'route': '/gerer-commandes'});
print("Menus par défaut insérés");
} else {
// Si des menus existent déjà, vérifier et ajouter les nouveaux menus manquants
await _addMissingMenus(db);
}
}
Future<void> _addMissingMenus(Database db) async {
final menusToAdd = [
{'name': 'Nouvelle commande', 'route': '/nouvelle-commande'},
{'name': 'Gérer les commandes', 'route': '/gerer-commandes'},
{'name': 'Gérer les pointages', 'route': '/pointage'},
];
for (var menu in menusToAdd) {
final existing = await db.query(
'menu',
where: 'route = ?',
whereArgs: [menu['route']],
);
if (existing.isEmpty) {
await db.insert('menu', menu);
print("Menu ajouté: ${menu['name']}");
}
}
}
Future<void> insertDefaultRoles() async {
final db = await database;
final existingRoles = await db.query('roles');
if (existingRoles.isEmpty) {
int superAdminRoleId =
await db.insert('roles', {'designation': 'Super Admin'});
int adminRoleId = await db.insert('roles', {'designation': 'Admin'});
int userRoleId = await db.insert('roles', {'designation': 'User'});
final permissions = await db.query('permissions');
final menus = await db.query('menu');
// Assigner toutes les permissions à tous les menus pour le Super Admin
for (var menu in menus) {
for (var permission in permissions) {
await db.insert(
'role_menu_permissions',
{
'role_id': superAdminRoleId,
'menu_id': menu['id'],
'permission_id': permission['id'],
},
conflictAlgorithm: ConflictAlgorithm.ignore);
}
}
// Assigner quelques permissions à l'Admin et à l'User pour les nouveaux menus
await _assignBasicPermissionsToRoles(db, adminRoleId, userRoleId);
print("Rôles par défaut créés et permissions assignées");
} else {
// Si les rôles existent déjà, vérifier et ajouter les permissions manquantes
await _updateExistingRolePermissions(db);
}
}
// Nouvelle méthode pour assigner les permissions de base aux nouveaux menus
Future<void> _assignBasicPermissionsToRoles(
Database db, int adminRoleId, int userRoleId) async {
final viewPermission =
await db.query('permissions', where: 'name = ?', whereArgs: ['view']);
final createPermission =
await db.query('permissions', where: 'name = ?', whereArgs: ['create']);
final updatePermission =
await db.query('permissions', where: 'name = ?', whereArgs: ['update']);
final managePermission =
await db.query('permissions', where: 'name = ?', whereArgs: ['manage']);
// Récupérer les IDs des nouveaux menus
final nouvelleCommandeMenu = await db
.query('menu', where: 'route = ?', whereArgs: ['/nouvelle-commande']);
final gererCommandesMenu = await db
.query('menu', where: 'route = ?', whereArgs: ['/gerer-commandes']);
if (nouvelleCommandeMenu.isNotEmpty && createPermission.isNotEmpty) {
// Admin peut créer de nouvelles commandes
await db.insert(
'role_menu_permissions',
{
'role_id': adminRoleId,
'menu_id': nouvelleCommandeMenu.first['id'],
'permission_id': createPermission.first['id'],
},
conflictAlgorithm: ConflictAlgorithm.ignore);
// User peut aussi créer de nouvelles commandes
await db.insert(
'role_menu_permissions',
{
'role_id': userRoleId,
'menu_id': nouvelleCommandeMenu.first['id'],
'permission_id': createPermission.first['id'],
},
conflictAlgorithm: ConflictAlgorithm.ignore);
}
if (gererCommandesMenu.isNotEmpty && managePermission.isNotEmpty) {
// Admin peut gérer les commandes
await db.insert(
'role_menu_permissions',
{
'role_id': adminRoleId,
'menu_id': gererCommandesMenu.first['id'],
'permission_id': managePermission.first['id'],
},
conflictAlgorithm: ConflictAlgorithm.ignore);
}
if (gererCommandesMenu.isNotEmpty && viewPermission.isNotEmpty) {
// User peut voir les commandes
await db.insert(
'role_menu_permissions',
{
'role_id': userRoleId,
'menu_id': gererCommandesMenu.first['id'],
'permission_id': viewPermission.first['id'],
},
conflictAlgorithm: ConflictAlgorithm.ignore);
}
}
Future<void> _updateExistingRolePermissions(Database db) async {
final superAdminRole = await db
.query('roles', where: 'designation = ?', whereArgs: ['Super Admin']);
if (superAdminRole.isNotEmpty) {
final superAdminRoleId = superAdminRole.first['id'] as int;
final permissions = await db.query('permissions');
final menus = await db.query('menu');
// Vérifier et ajouter les permissions manquantes pour le Super Admin sur tous les menus
for (var menu in menus) {
for (var permission in permissions) {
final existingPermission = await db.query(
'role_menu_permissions',
where: 'role_id = ? AND menu_id = ? AND permission_id = ?',
whereArgs: [superAdminRoleId, menu['id'], permission['id']],
);
if (existingPermission.isEmpty) {
await db.insert(
'role_menu_permissions',
{
'role_id': superAdminRoleId,
'menu_id': menu['id'],
'permission_id': permission['id'],
},
conflictAlgorithm: ConflictAlgorithm.ignore);
}
}
}
// Assigner les permissions de base aux autres rôles pour les nouveaux menus
final adminRole = await db
.query('roles', where: 'designation = ?', whereArgs: ['Admin']);
final userRole = await db
.query('roles', where: 'designation = ?', whereArgs: ['User']);
if (adminRole.isNotEmpty && userRole.isNotEmpty) {
await _assignBasicPermissionsToRoles(
db, adminRole.first['id'] as int, userRole.first['id'] as int);
}
print("Permissions mises à jour pour tous les rôles");
}
}
Future<void> insertDefaultSuperAdmin() async {
final db = await database;
final existingSuperAdmin = await db.rawQuery('''
SELECT u.* FROM users u
INNER JOIN roles r ON u.role_id = r.id
WHERE r.designation = 'Super Admin'
''');
if (existingSuperAdmin.isEmpty) {
final superAdminRole = await db
.query('roles', where: 'designation = ?', whereArgs: ['Super Admin']);
if (superAdminRole.isNotEmpty) {
final superAdminRoleId = superAdminRole.first['id'] as int;
await db.insert('users', {
'name': 'Super',
'lastname': 'Admin',
'email': 'superadmin@youmazgestion.com',
'password': 'admin123',
'username': 'superadmin',
'role_id': superAdminRoleId,
});
print("Super Admin créé avec succès !");
print("Username: superadmin");
print("Password: admin123");
print(
"ATTENTION: Changez ce mot de passe après la première connexion !");
}
} else {
print("Super Admin existe déjà");
}
}
Future<int> createUser(Users user) async {
final db = await database;
return await db.insert('users', user.toMap());
}
Future<int> deleteUser(int id) async {
final db = await database;
return await db.delete('users', where: 'id = ?', whereArgs: [id]);
}
Future<int> updateUser(Users user) async {
final db = await database;
return await db
.update('users', user.toMap(), where: 'id = ?', whereArgs: [user.id]);
}
Future<int> getUserCount() async {
final db = await database;
List<Map<String, dynamic>> result =
await db.rawQuery('SELECT COUNT(*) as count FROM users');
return result.first['count'] as int;
}
Future<bool> verifyUser(String username, String password) async {
final db = await database;
final result = await db.rawQuery('''
SELECT users.id
FROM users
WHERE users.username = ? AND users.password = ?
''', [username, password]);
return result.isNotEmpty;
}
Future<Users> getUser(String username) async {
final db = await database;
final result = await db.rawQuery('''
SELECT users.*, roles.designation as role_name
FROM users
INNER JOIN roles ON users.role_id = roles.id
WHERE users.username = ?
''', [username]);
if (result.isNotEmpty) {
return Users.fromMap(result.first);
} else {
throw Exception('User not found');
}
}
Future<Map<String, dynamic>?> getUserCredentials(
String username, String password) async {
final db = await database;
final result = await db.rawQuery('''
SELECT users.username, users.id, roles.designation as role_name, roles.id as role_id
FROM users
INNER JOIN roles ON users.role_id = roles.id
WHERE username = ? AND password = ?
''', [username, password]);
if (result.isNotEmpty) {
return {
'id': result.first['id'],
'username': result.first['username'] as String,
'role': result.first['role_name'] as String,
'role_id': result.first['role_id'],
};
} else {
return null;
}
}
Future<List<Users>> getAllUsers() async {
final db = await database;
final result = await db.rawQuery('''
SELECT users.*, roles.designation as role_name
FROM users
INNER JOIN roles ON users.role_id = roles.id
ORDER BY users.id ASC
''');
return result.map((json) => Users.fromMap(json)).toList();
}
Future<int> createRole(Role role) async {
final db = await database;
return await db.insert('roles', role.toMap());
}
Future<List<Role>> getRoles() async {
final db = await database;
final maps = await db.query('roles', orderBy: 'designation ASC');
return List.generate(maps.length, (i) => Role.fromMap(maps[i]));
}
Future<int> updateRole(Role role) async {
final db = await database;
return await db.update(
'roles',
role.toMap(),
where: 'id = ?',
whereArgs: [role.id],
);
}
Future<int> deleteRole(int? id) async {
final db = await database;
return await db.delete(
'roles',
where: 'id = ?',
whereArgs: [id],
);
}
Future<List<Permission>> getAllPermissions() async {
final db = await database;
final result = await db.query('permissions', orderBy: 'name ASC');
return result.map((e) => Permission.fromMap(e)).toList();
}
Future<List<Permission>> getPermissionsForRole(int roleId) async {
final db = await database;
final result = await db.rawQuery('''
SELECT p.id, p.name
FROM permissions p
JOIN role_permissions rp ON p.id = rp.permission_id
WHERE rp.role_id = ?
ORDER BY p.name ASC
''', [roleId]);
return result.map((map) => Permission.fromMap(map)).toList();
}
Future<List<Permission>> getPermissionsForUser(String username) async {
final db = await database;
final result = await db.rawQuery('''
SELECT DISTINCT p.id, p.name
FROM permissions p
JOIN role_permissions rp ON p.id = rp.permission_id
JOIN roles r ON rp.role_id = r.id
JOIN users u ON u.role_id = r.id
WHERE u.username = ?
ORDER BY p.name ASC
''', [username]);
return result.map((map) => Permission.fromMap(map)).toList();
}
Future<void> assignPermission(int roleId, int permissionId) async {
final db = await database;
await db.insert(
'role_permissions',
{
'role_id': roleId,
'permission_id': permissionId,
},
conflictAlgorithm: ConflictAlgorithm.ignore);
}
Future<void> removePermission(int roleId, int permissionId) async {
final db = await database;
await db.delete(
'role_permissions',
where: 'role_id = ? AND permission_id = ?',
whereArgs: [roleId, permissionId],
);
}
Future<void> assignMenuPermission(int menuId, int permissionId) async {
final db = await database;
await db.insert(
'menu_permissions',
{
'menu_id': menuId,
'permission_id': permissionId,
},
conflictAlgorithm: ConflictAlgorithm.ignore);
}
Future<void> removeMenuPermission(int menuId, int permissionId) async {
final db = await database;
await db.delete(
'menu_permissions',
where: 'menu_id = ? AND permission_id = ?',
whereArgs: [menuId, permissionId],
);
}
Future<bool> isSuperAdmin(String username) async {
final db = await database;
final result = await db.rawQuery('''
SELECT COUNT(*) as count
FROM users u
INNER JOIN roles r ON u.role_id = r.id
WHERE u.username = ? AND r.designation = 'Super Admin'
''', [username]);
return (result.first['count'] as int) > 0;
}
Future<void> changePassword(
String username, String oldPassword, String newPassword) async {
final db = await database;
final isValidOldPassword = await verifyUser(username, oldPassword);
if (!isValidOldPassword) {
throw Exception('Ancien mot de passe incorrect');
}
await db.update(
'users',
{'password': newPassword},
where: 'username = ?',
whereArgs: [username],
);
}
Future<bool> hasPermission(
String username, String permissionName, String menuRoute) async {
final db = await database;
final result = await db.rawQuery('''
SELECT COUNT(*) as count
FROM permissions p
JOIN role_menu_permissions rmp ON p.id = rmp.permission_id
JOIN roles r ON rmp.role_id = r.id
JOIN users u ON u.role_id = r.id
JOIN menu m ON m.route = ?
WHERE u.username = ? AND p.name = ? AND rmp.menu_id = m.id
''', [menuRoute, username, permissionName]);
return (result.first['count'] as int) > 0;
}
Future<void> close() async {
if (_database.isOpen) {
await _database.close();
}
}
Future<void> printDatabaseInfo() async {
final db = await database;
print("=== INFORMATIONS DE LA BASE DE DONNÉES ===");
final userCount = await getUserCount();
print("Nombre d'utilisateurs: $userCount");
final users = await getAllUsers();
print("Utilisateurs:");
for (var user in users) {
print(" - ${user.username} (${user.name} ) - Email: ${user.email}");
}
final roles = await getRoles();
print("Rôles:");
for (var role in roles) {
print(" - ${role.designation} (ID: ${role.id})");
}
final permissions = await getAllPermissions();
print("Permissions:");
for (var permission in permissions) {
print(" - ${permission.name} (ID: ${permission.id})");
}
print("=========================================");
}
Future<List<Permission>> getPermissionsForRoleAndMenu(
int roleId, int menuId) async {
final db = await database;
final result = await db.rawQuery('''
SELECT p.id, p.name
FROM permissions p
JOIN role_menu_permissions rmp ON p.id = rmp.permission_id
WHERE rmp.role_id = ? AND rmp.menu_id = ?
ORDER BY p.name ASC
''', [roleId, menuId]);
return result.map((map) => Permission.fromMap(map)).toList();
}
// Ajoutez cette méthode temporaire pour supprimer la DB corrompue
Future<void> deleteDatabaseFile() async {
final documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, 'app_database.db');
final file = File(path);
if (await file.exists()) {
await file.delete();
print("Base de données utilisateur supprimée");
}
}
Future<void> assignRoleMenuPermission(
int roleId, int menuId, int permissionId) async {
final db = await database;
await db.insert(
'role_menu_permissions',
{
'role_id': roleId,
'menu_id': menuId,
'permission_id': permissionId,
},
conflictAlgorithm: ConflictAlgorithm.ignore);
}
Future<void> removeRoleMenuPermission(
int roleId, int menuId, int permissionId) async {
final db = await database;
await db.delete(
'role_menu_permissions',
where: 'role_id = ? AND menu_id = ? AND permission_id = ?',
whereArgs: [roleId, menuId, permissionId],
);
}
}

View File

@ -0,0 +1,559 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import '../Models/produit.dart';
import '../Models/client.dart';
class ProductDatabase {
static final ProductDatabase instance = ProductDatabase._init();
late Database _database;
ProductDatabase._init() {
sqfliteFfiInit();
}
ProductDatabase();
Future<Database> get database async {
if (_database.isOpen) return _database;
_database = await _initDB('products2.db');
return _database;
}
Future<void> initDatabase() async {
_database = await _initDB('products2.db');
await _createDB(_database, 1);
await _insertDefaultClients();
await _insertDefaultCommandes();
}
Future<Database> _initDB(String filePath) async {
final documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, filePath);
bool dbExists = await File(path).exists();
if (!dbExists) {
try {
ByteData data = await rootBundle.load('assets/database/$filePath');
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
await File(path).writeAsBytes(bytes);
} catch (e) {
print('Pas de fichier DB dans assets, création nouvelle DB');
}
}
return await databaseFactoryFfi.openDatabase(path);
}
Future<void> _createDB(Database db, int version) async {
final tables = await db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'");
final tableNames = tables.map((row) => row['name'] as String).toList();
// Table products (existante avec améliorations)
if (!tableNames.contains('products')) {
await db.execute('''
CREATE TABLE products(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL NOT NULL,
image TEXT,
category TEXT NOT NULL,
stock INTEGER NOT NULL DEFAULT 0,
description TEXT,
qrCode TEXT,
reference TEXT UNIQUE
)
''');
print("Table 'products' créée.");
} else {
// Vérifier et ajouter les colonnes manquantes
await _updateProductsTable(db);
}
// Table clients
if (!tableNames.contains('clients')) {
await db.execute('''
CREATE TABLE clients(
id INTEGER PRIMARY KEY AUTOINCREMENT,
nom TEXT NOT NULL,
prenom TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
telephone TEXT NOT NULL,
adresse TEXT,
dateCreation TEXT NOT NULL,
actif INTEGER NOT NULL DEFAULT 1
)
''');
print("Table 'clients' créée.");
}
// Table commandes
if (!tableNames.contains('commandes')) {
await db.execute('''
CREATE TABLE commandes(
id INTEGER PRIMARY KEY AUTOINCREMENT,
clientId INTEGER NOT NULL,
dateCommande TEXT NOT NULL,
statut INTEGER NOT NULL DEFAULT 0,
montantTotal REAL NOT NULL,
notes TEXT,
dateLivraison TEXT,
FOREIGN KEY (clientId) REFERENCES clients(id) ON DELETE CASCADE
)
''');
print("Table 'commandes' créée.");
}
// Table détails commandes
if (!tableNames.contains('details_commandes')) {
await db.execute('''
CREATE TABLE details_commandes(
id INTEGER PRIMARY KEY AUTOINCREMENT,
commandeId INTEGER NOT NULL,
produitId INTEGER NOT NULL,
quantite INTEGER NOT NULL,
prixUnitaire REAL NOT NULL,
sousTotal REAL NOT NULL,
FOREIGN KEY (commandeId) REFERENCES commandes(id) ON DELETE CASCADE,
FOREIGN KEY (produitId) REFERENCES products(id) ON DELETE CASCADE
)
''');
print("Table 'details_commandes' créée.");
}
// Créer les index pour optimiser les performances
await _createIndexes(db);
}
Future<void> _updateProductsTable(Database db) async {
final columns = await db.rawQuery('PRAGMA table_info(products)');
final columnNames = columns.map((e) => e['name'] as String).toList();
if (!columnNames.contains('description')) {
await db.execute("ALTER TABLE products ADD COLUMN description TEXT");
print("Colonne 'description' ajoutée.");
}
if (!columnNames.contains('qrCode')) {
await db.execute("ALTER TABLE products ADD COLUMN qrCode TEXT");
print("Colonne 'qrCode' ajoutée.");
}
if (!columnNames.contains('reference')) {
await db.execute("ALTER TABLE products ADD COLUMN reference TEXT");
print("Colonne 'reference' ajoutée.");
}
}
Future<void> _createIndexes(Database db) async {
await db.execute('CREATE INDEX IF NOT EXISTS idx_products_category ON products(category)');
await db.execute('CREATE INDEX IF NOT EXISTS idx_products_reference ON products(reference)');
await db.execute('CREATE INDEX IF NOT EXISTS idx_commandes_client ON commandes(clientId)');
await db.execute('CREATE INDEX IF NOT EXISTS idx_commandes_date ON commandes(dateCommande)');
await db.execute('CREATE INDEX IF NOT EXISTS idx_details_commande ON details_commandes(commandeId)');
print("Index créés pour optimiser les performances.");
}
// =========================
// MÉTHODES PRODUCTS (existantes)
// =========================
Future<int> createProduct(Product product) async {
final db = await database;
return await db.insert('products', product.toMap());
}
Future<List<Product>> getProducts() async {
final db = await database;
final maps = await db.query('products', orderBy: 'name ASC');
return List.generate(maps.length, (i) {
return Product.fromMap(maps[i]);
});
}
Future<int> updateProduct(Product product) async {
final db = await database;
return await db.update(
'products',
product.toMap(),
where: 'id = ?',
whereArgs: [product.id],
);
}
Future<int> deleteProduct(int? id) async {
final db = await database;
return await db.delete(
'products',
where: 'id = ?',
whereArgs: [id],
);
}
Future<List<String>> getCategories() async {
final db = await database;
final result = await db.rawQuery('SELECT DISTINCT category FROM products ORDER BY category');
return List.generate(
result.length, (index) => result[index]['category'] as String);
}
Future<List<Product>> getProductsByCategory(String category) async {
final db = await database;
final maps = await db
.query('products', where: 'category = ?', whereArgs: [category], orderBy: 'name ASC');
return List.generate(maps.length, (i) {
return Product.fromMap(maps[i]);
});
}
Future<int> updateStock(int id, int stock) async {
final db = await database;
return await db
.rawUpdate('UPDATE products SET stock = ? WHERE id = ?', [stock, id]);
}
Future<Product?> getProductByReference(String reference) async {
final db = await database;
final maps = await db.query(
'products',
where: 'reference = ?',
whereArgs: [reference],
);
if (maps.isNotEmpty) {
return Product.fromMap(maps.first);
}
return null;
}
// =========================
// MÉTHODES CLIENTS
// =========================
Future<int> createClient(Client client) async {
final db = await database;
return await db.insert('clients', client.toMap());
}
Future<List<Client>> getClients() async {
final db = await database;
final maps = await db.query('clients', where: 'actif = 1', orderBy: 'nom ASC, prenom ASC');
return List.generate(maps.length, (i) {
return Client.fromMap(maps[i]);
});
}
Future<Client?> getClientById(int id) async {
final db = await database;
final maps = await db.query('clients', where: 'id = ?', whereArgs: [id]);
if (maps.isNotEmpty) {
return Client.fromMap(maps.first);
}
return null;
}
Future<int> updateClient(Client client) async {
final db = await database;
return await db.update(
'clients',
client.toMap(),
where: 'id = ?',
whereArgs: [client.id],
);
}
Future<int> deleteClient(int id) async {
final db = await database;
// Soft delete
return await db.update(
'clients',
{'actif': 0},
where: 'id = ?',
whereArgs: [id],
);
}
Future<List<Client>> searchClients(String query) async {
final db = await database;
final maps = await db.query(
'clients',
where: 'actif = 1 AND (nom LIKE ? OR prenom LIKE ? OR email LIKE ?)',
whereArgs: ['%$query%', '%$query%', '%$query%'],
orderBy: 'nom ASC, prenom ASC',
);
return List.generate(maps.length, (i) {
return Client.fromMap(maps[i]);
});
}
// =========================
// MÉTHODES COMMANDES
// =========================
Future<int> createCommande(Commande commande) async {
final db = await database;
return await db.insert('commandes', commande.toMap());
}
Future<List<Commande>> getCommandes() async {
final db = await database;
final maps = await db.rawQuery('''
SELECT c.*, cl.nom as clientNom, cl.prenom as clientPrenom, cl.email as clientEmail
FROM commandes c
LEFT JOIN clients cl ON c.clientId = cl.id
ORDER BY c.dateCommande DESC
''');
return List.generate(maps.length, (i) {
return Commande.fromMap(maps[i]);
});
}
Future<List<Commande>> getCommandesByClient(int clientId) async {
final db = await database;
final maps = await db.rawQuery('''
SELECT c.*, cl.nom as clientNom, cl.prenom as clientPrenom, cl.email as clientEmail
FROM commandes c
LEFT JOIN clients cl ON c.clientId = cl.id
WHERE c.clientId = ?
ORDER BY c.dateCommande DESC
''', [clientId]);
return List.generate(maps.length, (i) {
return Commande.fromMap(maps[i]);
});
}
Future<Commande?> getCommandeById(int id) async {
final db = await database;
final maps = await db.rawQuery('''
SELECT c.*, cl.nom as clientNom, cl.prenom as clientPrenom, cl.email as clientEmail
FROM commandes c
LEFT JOIN clients cl ON c.clientId = cl.id
WHERE c.id = ?
''', [id]);
if (maps.isNotEmpty) {
return Commande.fromMap(maps.first);
}
return null;
}
Future<int> updateCommande(Commande commande) async {
final db = await database;
return await db.update(
'commandes',
commande.toMap(),
where: 'id = ?',
whereArgs: [commande.id],
);
}
Future<int> updateStatutCommande(int commandeId, StatutCommande statut) async {
final db = await database;
return await db.update(
'commandes',
{'statut': statut.index},
where: 'id = ?',
whereArgs: [commandeId],
);
}
// =========================
// MÉTHODES DÉTAILS COMMANDES
// =========================
Future<int> createDetailCommande(DetailCommande detail) async {
final db = await database;
return await db.insert('details_commandes', detail.toMap());
}
Future<List<DetailCommande>> getDetailsCommande(int commandeId) async {
final db = await database;
final maps = await db.rawQuery('''
SELECT dc.*, p.name as produitNom, p.image as produitImage, p.reference as produitReference
FROM details_commandes dc
LEFT JOIN products p ON dc.produitId = p.id
WHERE dc.commandeId = ?
ORDER BY dc.id
''', [commandeId]);
return List.generate(maps.length, (i) {
return DetailCommande.fromMap(maps[i]);
});
}
// =========================
// MÉTHODES TRANSACTION COMPLÈTE
// =========================
Future<int> createCommandeComplete(Client client, Commande commande, List<DetailCommande> details) async {
final db = await database;
return await db.transaction((txn) async {
// Créer le client
final clientId = await txn.insert('clients', client.toMap());
// Créer la commande
final commandeMap = commande.toMap();
commandeMap['clientId'] = clientId;
final commandeId = await txn.insert('commandes', commandeMap);
// Créer les détails et mettre à jour le stock
for (var detail in details) {
final detailMap = detail.toMap();
detailMap['commandeId'] = commandeId; // Ajoute l'ID de la commande
await txn.insert('details_commandes', detailMap);
// Mettre à jour le stock du produit
await txn.rawUpdate(
'UPDATE products SET stock = stock - ? WHERE id = ?',
[detail.quantite, detail.produitId],
);
}
return commandeId;
});
}
// =========================
// STATISTIQUES
// =========================
Future<Map<String, dynamic>> getStatistiques() async {
final db = await database;
final totalClients = await db.rawQuery('SELECT COUNT(*) as count FROM clients WHERE actif = 1');
final totalCommandes = await db.rawQuery('SELECT COUNT(*) as count FROM commandes');
final totalProduits = await db.rawQuery('SELECT COUNT(*) as count FROM products');
final chiffreAffaires = await db.rawQuery('SELECT SUM(montantTotal) as total FROM commandes WHERE statut != 5'); // 5 = annulée
return {
'totalClients': totalClients.first['count'],
'totalCommandes': totalCommandes.first['count'],
'totalProduits': totalProduits.first['count'],
'chiffreAffaires': chiffreAffaires.first['total'] ?? 0.0,
};
}
// =========================
// DONNÉES PAR DÉFAUT
// =========================
Future<void> _insertDefaultClients() async {
final db = await database;
final existingClients = await db.query('clients');
if (existingClients.isEmpty) {
final defaultClients = [
Client(
nom: 'Dupont',
prenom: 'Jean',
email: 'jean.dupont@email.com',
telephone: '0123456789',
adresse: '123 Rue de la Paix, Paris',
dateCreation: DateTime.now(),
),
Client(
nom: 'Martin',
prenom: 'Marie',
email: 'marie.martin@email.com',
telephone: '0987654321',
adresse: '456 Avenue des Champs, Lyon',
dateCreation: DateTime.now(),
),
Client(
nom: 'Bernard',
prenom: 'Pierre',
email: 'pierre.bernard@email.com',
telephone: '0456789123',
adresse: '789 Boulevard Saint-Michel, Marseille',
dateCreation: DateTime.now(),
),
];
for (var client in defaultClients) {
await db.insert('clients', client.toMap());
}
print("Clients par défaut insérés");
}
}
Future<void> _insertDefaultCommandes() async {
final db = await database;
final existingCommandes = await db.query('commandes');
if (existingCommandes.isEmpty) {
// Récupérer quelques produits pour créer des commandes
final produits = await db.query('products', limit: 3);
final clients = await db.query('clients', limit: 3);
if (produits.isNotEmpty && clients.isNotEmpty) {
// Commande 1
final commande1Id = await db.insert('commandes', {
'clientId': clients[0]['id'],
'dateCommande': DateTime.now().subtract(Duration(days: 5)).toIso8601String(),
'statut': StatutCommande.livree.index,
'montantTotal': 150.0,
'notes': 'Commande urgente',
});
await db.insert('details_commandes', {
'commandeId': commande1Id,
'produitId': produits[0]['id'],
'quantite': 2,
'prixUnitaire': 75.0,
'sousTotal': 150.0,
});
// Commande 2
final commande2Id = await db.insert('commandes', {
'clientId': clients[1]['id'],
'dateCommande': DateTime.now().subtract(Duration(days: 2)).toIso8601String(),
'statut': StatutCommande.enPreparation.index,
'montantTotal': 225.0,
'notes': 'Livraison prévue demain',
});
if (produits.length > 1) {
await db.insert('details_commandes', {
'commandeId': commande2Id,
'produitId': produits[1]['id'],
'quantite': 3,
'prixUnitaire': 75.0,
'sousTotal': 225.0,
});
}
// Commande 3
final commande3Id = await db.insert('commandes', {
'clientId': clients[2]['id'],
'dateCommande': DateTime.now().subtract(Duration(hours: 6)).toIso8601String(),
'statut': StatutCommande.confirmee.index,
'montantTotal': 300.0,
'notes': 'Commande standard',
});
if (produits.length > 2) {
await db.insert('details_commandes', {
'commandeId': commande3Id,
'produitId': produits[2]['id'],
'quantite': 4,
'prixUnitaire': 75.0,
'sousTotal': 300.0,
});
}
print("Commandes par défaut insérées");
}
}
}
Future<void> close() async {
if (_database.isOpen) {
await _database.close();
}
}
// Ajoutez cette méthode temporaire pour supprimer la DB corrompue
Future<void> deleteDatabaseFile() async {
final documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, 'products2.db');
final file = File(path);
if (await file.exists()) {
await file.delete();
print("Base de données product supprimée");
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:youmazgestion/Components/app_bar.dart'; import 'package:youmazgestion/Components/app_bar.dart';
//import 'package:youmazgestion/Models/Permission.dart'; import 'package:youmazgestion/Models/Permission.dart';
//import 'package:youmazgestion/Services/app_database.dart'; import 'package:youmazgestion/Services/app_database.dart';
import 'package:youmazgestion/Models/role.dart'; import 'package:youmazgestion/Models/role.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import 'package:youmazgestion/Views/RolePermissionPage.dart'; import 'package:youmazgestion/Views/RolePermissionPage.dart';
class RoleListPage extends StatefulWidget { class RoleListPage extends StatefulWidget {
@ -48,7 +47,7 @@ class _RoleListPageState extends State<RoleListPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar(title: "Gestion des rôles"), appBar: const CustomAppBar(title: "Gestion des rôles"),
body: Padding( body: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(

View File

@ -1,9 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:youmazgestion/Components/app_bar.dart'; import 'package:youmazgestion/Components/app_bar.dart';
import 'package:youmazgestion/Models/Permission.dart'; import 'package:youmazgestion/Models/Permission.dart';
import 'package:youmazgestion/Services/app_database.dart';
import 'package:youmazgestion/Models/role.dart'; import 'package:youmazgestion/Models/role.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
class RolePermissionsPage extends StatefulWidget { class RolePermissionsPage extends StatefulWidget {
final Role role; final Role role;

View File

@ -29,7 +29,7 @@ class _BilanMoisState extends State<BilanMois> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar(title: 'Bilan du mois'), appBar: const CustomAppBar(title: 'Bilan du mois'),
body: Column( body: Column(
children: [ children: [
// Les 3 cartes en haut // Les 3 cartes en haut

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import '../Models/produit.dart'; import '../Models/produit.dart';
//import '../Services/productDatabase.dart'; import '../Services/productDatabase.dart';
import 'gestionProduct.dart'; import 'gestionProduct.dart';
class EditProductPage extends StatelessWidget { class EditProductPage extends StatelessWidget {
@ -32,7 +31,7 @@ class EditProductPage extends StatelessWidget {
category: category, category: category,
); );
await AppDatabase.instance.updateProduct(updatedProduct); await ProductDatabase.instance.updateProduct(updatedProduct);
Get.to(GestionProduit()); Get.to(GestionProduit());
} else { } else {

View File

@ -1,8 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:youmazgestion/Models/users.dart'; import 'package:youmazgestion/Models/users.dart';
import 'package:youmazgestion/Models/role.dart'; import 'package:youmazgestion/Models/role.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart'; import '../Services/app_database.dart';
//import '../Services/app_database.dart';
class EditUserPage extends StatefulWidget { class EditUserPage extends StatefulWidget {
final Users user; final Users user;

View File

@ -1,15 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:youmazgestion/Components/app_bar.dart'; import 'package:youmazgestion/Components/app_bar.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import '../Components/appDrawer.dart'; import '../Components/appDrawer.dart';
import '../Models/produit.dart'; import '../Models/produit.dart';
// import '../Services/productDatabase.dart'; import '../Services/productDatabase.dart';
import 'editProduct.dart'; import 'editProduct.dart';
import 'dart:io'; import 'dart:io';
class GestionProduit extends StatelessWidget { class GestionProduit extends StatelessWidget {
final AppDatabase _productDatabase = AppDatabase.instance; final ProductDatabase _productDatabase = ProductDatabase.instance;
GestionProduit({super.key}); GestionProduit({super.key});
@ -18,7 +17,7 @@ class GestionProduit extends StatelessWidget {
final screenWidth = MediaQuery.of(context).size.width * 0.8; final screenWidth = MediaQuery.of(context).size.width * 0.8;
return Scaffold( return Scaffold(
appBar: CustomAppBar(title: 'Gestion des produits'), appBar: const CustomAppBar(title: 'Gestion des produits'),
drawer: CustomDrawer(), drawer: CustomDrawer(),
body: FutureBuilder<List<Product>>( body: FutureBuilder<List<Product>>(
future: _productDatabase.getProducts(), future: _productDatabase.getProducts(),

View File

@ -1,9 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:youmazgestion/Components/app_bar.dart'; import 'package:youmazgestion/Components/app_bar.dart';
import 'package:youmazgestion/Models/Permission.dart'; import 'package:youmazgestion/Models/Permission.dart';
//import 'package:youmazgestion/Services/app_database.dart'; import 'package:youmazgestion/Services/app_database.dart';
import 'package:youmazgestion/Models/role.dart'; import 'package:youmazgestion/Models/role.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
class HandleUserRole extends StatefulWidget { class HandleUserRole extends StatefulWidget {
const HandleUserRole({super.key}); const HandleUserRole({super.key});
@ -84,7 +83,7 @@ class _HandleUserRoleState extends State<HandleUserRole> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar(title: "Gestion des rôles"), appBar: const CustomAppBar(title: "Gestion des rôles"),
body: Padding( body: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(

View File

@ -2,10 +2,9 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart'; import 'package:get/get_core/src/get_main.dart';
import 'package:youmazgestion/Models/produit.dart'; import 'package:youmazgestion/Models/produit.dart';
//import 'package:youmazgestion/Services/productDatabase.dart'; import 'package:youmazgestion/Services/productDatabase.dart';
import 'package:youmazgestion/Components/app_bar.dart'; import 'package:youmazgestion/Components/app_bar.dart';
import 'package:youmazgestion/Components/appDrawer.dart'; import 'package:youmazgestion/Components/appDrawer.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
class GestionStockPage extends StatefulWidget { class GestionStockPage extends StatefulWidget {
const GestionStockPage({super.key}); const GestionStockPage({super.key});
@ -15,7 +14,7 @@ class GestionStockPage extends StatefulWidget {
} }
class _GestionStockPageState extends State<GestionStockPage> { class _GestionStockPageState extends State<GestionStockPage> {
final AppDatabase _database = AppDatabase.instance; final ProductDatabase _database = ProductDatabase.instance;
List<Product> _products = []; List<Product> _products = [];
List<Product> _filteredProducts = []; List<Product> _filteredProducts = [];
String? _selectedCategory; String? _selectedCategory;
@ -80,7 +79,7 @@ class _GestionStockPageState extends State<GestionStockPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar(title: 'Gestion des Stocks'), appBar: const CustomAppBar(title: 'Gestion des Stocks'),
drawer: CustomDrawer(), drawer: CustomDrawer(),
body: Column( body: Column(
children: [ children: [

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,7 @@ class HistoryDetailPage extends StatelessWidget {
init: controller, init: controller,
builder: (controller) { builder: (controller) {
return Scaffold( return Scaffold(
appBar: CustomAppBar(title: 'Historique de la journée'), appBar: const CustomAppBar(title: 'Historique de la journée'),
body: Column( body: Column(
children: [ children: [
Padding( Padding(

View File

@ -1,9 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:youmazgestion/Models/users.dart'; import 'package:youmazgestion/Models/users.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import '../Components/app_bar.dart'; import '../Components/app_bar.dart';
//import '../Services/app_database.dart'; import '../Services/app_database.dart';
import 'editUser.dart'; import 'editUser.dart';
class ListUserPage extends StatefulWidget { class ListUserPage extends StatefulWidget {
@ -36,7 +35,7 @@ class _ListUserPageState extends State<ListUserPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar(title: 'Liste des utilisateurs'), appBar: const CustomAppBar(title: 'Liste des utilisateurs'),
body: ListView.builder( body: ListView.builder(
itemCount: userList.length, itemCount: userList.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {

View File

@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:youmazgestion/Views/Dashboard.dart';
import 'package:youmazgestion/Views/mobilepage.dart';
import 'package:youmazgestion/Views/particles.dart' show ParticleBackground; import 'package:youmazgestion/Views/particles.dart' show ParticleBackground;
import 'package:youmazgestion/accueil.dart'; import 'package:youmazgestion/accueil.dart';
import 'package:youmazgestion/Services/app_database.dart';
import '../Models/users.dart'; import '../Models/users.dart';
import '../controller/userController.dart'; import '../controller/userController.dart';
@ -34,7 +34,7 @@ class _LoginPageState extends State<LoginPage> {
void checkUserCount() async { void checkUserCount() async {
try { try {
final userCount = await AppDatabase.instance.getUserCount(); final userCount = await AppDatabase.instance.getUserCount();
print('Nombre d\'utilisateurs trouvés: $userCount'); print('Nombre d\'utilisateurs trouvés: $userCount'); // Debug
} catch (error) { } catch (error) {
print('Erreur lors de la vérification du nombre d\'utilisateurs: $error'); print('Erreur lors de la vérification du nombre d\'utilisateurs: $error');
setState(() { setState(() {
@ -54,12 +54,8 @@ class _LoginPageState extends State<LoginPage> {
Future<void> saveUserData(Users user, String role, int userId) async { Future<void> saveUserData(Users user, String role, int userId) async {
try { try {
userController.setUserWithCredentials(user, role, userId); userController.setUserWithCredentials(user, role, userId);
print(
if (user.pointDeVenteId != null) { 'Utilisateur sauvegardé: ${user.username}, rôle: $role, id: $userId');
await userController.loadPointDeVenteDesignation();
}
print('Utilisateur sauvegardé avec point de vente: ${userController.pointDeVenteDesignation}');
} catch (error) { } catch (error) {
print('Erreur lors de la sauvegarde: $error'); print('Erreur lors de la sauvegarde: $error');
throw Exception('Erreur lors de la sauvegarde des données utilisateur'); throw Exception('Erreur lors de la sauvegarde des données utilisateur');
@ -87,50 +83,27 @@ class _LoginPageState extends State<LoginPage> {
}); });
try { try {
print('Tentative de connexion pour: $username');
final dbInstance = AppDatabase.instance; final dbInstance = AppDatabase.instance;
try { // Vérifier les identifiants
final userCount = await dbInstance.getUserCount();
print('Base de données accessible, $userCount utilisateurs trouvés');
} catch (dbError) {
throw Exception('Impossible d\'accéder à la base de données: $dbError');
}
bool isValidUser = await dbInstance.verifyUser(username, password); bool isValidUser = await dbInstance.verifyUser(username, password);
if (isValidUser) { if (isValidUser) {
Users user = await dbInstance.getUser(username); Users user = await dbInstance.getUser(username);
print('Utilisateur récupéré: ${user.username}');
Map<String, dynamic>? userCredentials = Map<String, dynamic>? userCredentials =
await dbInstance.getUserCredentials(username, password); await dbInstance.getUserCredentials(username, password);
if (userCredentials != null) { if (userCredentials != null) {
print('Connexion réussie pour: ${user.username}');
print('Rôle: ${userCredentials['role']}');
print('ID: ${userCredentials['id']}');
await saveUserData( await saveUserData(
user, user,
userCredentials['role'] as String, userCredentials['role'] as String,
userCredentials['id'] as int, userCredentials['id'] as int,
); );
// MODIFICATION PRINCIPALE ICI
if (mounted) { if (mounted) {
if (userCredentials['role'] == 'commercial') { Navigator.pushReplacement(
// Redirection vers MainLayout pour les commerciaux context,
Navigator.pushReplacement( MaterialPageRoute(builder: (context) => const AccueilPage()),
context, );
MaterialPageRoute(builder: (context) => const MainLayout()),
);
} else {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => DashboardPage()),
);
}
} }
} else { } else {
throw Exception('Erreur lors de la récupération des credentials'); throw Exception('Erreur lors de la récupération des credentials');

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:youmazgestion/Models/users.dart'; import 'package:youmazgestion/Models/users.dart';
import 'package:youmazgestion/Models/role.dart'; import 'package:youmazgestion/Models/role.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import 'package:youmazgestion/Views/Dashboard.dart';
import 'package:youmazgestion/accueil.dart'; import 'package:youmazgestion/accueil.dart';
//import '../Services/app_database.dart'; // Changé de authDatabase.dart import '../Services/app_database.dart'; // Changé de authDatabase.dart
class RegistrationPage extends StatefulWidget { class RegistrationPage extends StatefulWidget {
const RegistrationPage({super.key}); const RegistrationPage({super.key});
@ -25,9 +23,7 @@ class _RegistrationPageState extends State<RegistrationPage> {
Role? _selectedRole; Role? _selectedRole;
bool _isLoading = false; bool _isLoading = false;
bool _isLoadingRoles = true; bool _isLoadingRoles = true;
List<Map<String, dynamic>> _availablePointsDeVente = [];
int? _selectedPointDeVenteId;
bool _isLoadingPointsDeVente = true;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -40,38 +36,19 @@ class _RegistrationPageState extends State<RegistrationPage> {
_initializeDatabase(); _initializeDatabase();
} }
Future<void> _initializeDatabase() async { Future<void> _initializeDatabase() async {
try { try {
await AppDatabase.instance.initDatabase(); await AppDatabase.instance.initDatabase();
await _loadRoles(); await _loadRoles();
await _loadPointsDeVente(); // Ajouté ici } catch (error) {
} catch (error) { print('Erreur lors de l\'initialisation: $error');
print('Erreur lors de l\'initialisation: $error'); if (mounted) {
if (mounted) { _showErrorDialog('Erreur d\'initialisation',
_showErrorDialog('Erreur d\'initialisation', 'Impossible d\'initialiser l\'application. Veuillez redémarrer.');
'Impossible d\'initialiser l\'application. Veuillez redémarrer.'); }
} }
} }
}
Future<void> _loadPointsDeVente() async {
try {
final points = await AppDatabase.instance.getPointsDeVente();
if (mounted) {
setState(() {
_availablePointsDeVente = points;
_isLoadingPointsDeVente = false;
});
}
} catch (error) {
print('Erreur lors du chargement des points de vente: $error');
if (mounted) {
setState(() {
_isLoadingPointsDeVente = false;
});
}
}
}
Future<void> _loadRoles() async { Future<void> _loadRoles() async {
try { try {
final roles = await AppDatabase.instance.getRoles(); final roles = await AppDatabase.instance.getRoles();
@ -121,16 +98,15 @@ Future<void> _loadPointsDeVente() async {
} }
bool _validateFields() { bool _validateFields() {
if (_nameController.text.trim().isEmpty || if (_nameController.text.trim().isEmpty ||
_lastNameController.text.trim().isEmpty || _lastNameController.text.trim().isEmpty ||
_emailController.text.trim().isEmpty || _emailController.text.trim().isEmpty ||
_usernameController.text.trim().isEmpty || _usernameController.text.trim().isEmpty ||
_passwordController.text.trim().isEmpty || _passwordController.text.trim().isEmpty ||
_selectedRole == null || _selectedRole == null) {
_selectedPointDeVenteId == null) { // Ajouté ici _showErrorDialog('Champs manquants', 'Veuillez remplir tous les champs.');
_showErrorDialog('Champs manquants', 'Veuillez remplir tous les champs.'); return false;
return false; }
}
// Validation basique de l'email // Validation basique de l'email
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(_emailController.text.trim())) { if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(_emailController.text.trim())) {
@ -150,24 +126,23 @@ Future<void> _loadPointsDeVente() async {
void _register() async { void _register() async {
if (_isLoading) return; if (_isLoading) return;
if (!_validateFields()) return; if (!_validateFields()) return;
setState(() { setState(() {
_isLoading = true; _isLoading = true;
}); });
try { try {
// Créer l'objet utilisateur avec le nouveau modèle // Créer l'objet utilisateur avec le nouveau modèle
final Users user = Users( final Users user = Users(
name: _nameController.text.trim(), name: _nameController.text.trim(),
lastName: _lastNameController.text.trim(), lastName: _lastNameController.text.trim(),
email: _emailController.text.trim(), email: _emailController.text.trim(),
password: _passwordController.text.trim(), password: _passwordController.text.trim(),
username: _usernameController.text.trim(), username: _usernameController.text.trim(),
roleId: _selectedRole!.id!, // Utiliser l'ID du rôle roleId: _selectedRole!.id!, // Utiliser l'ID du rôle
roleName: _selectedRole!.designation, // Pour l'affichage roleName: _selectedRole!.designation, // Pour l'affichage
pointDeVenteId: _selectedPointDeVenteId, // Ajouté ici );
);
// Sauvegarder l'utilisateur dans la base de données // Sauvegarder l'utilisateur dans la base de données
final int userId = await AppDatabase.instance.createUser(user); final int userId = await AppDatabase.instance.createUser(user);
@ -216,7 +191,7 @@ Future<void> _loadPointsDeVente() async {
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.pushReplacement( Navigator.pushReplacement(
context, context,
MaterialPageRoute(builder: (context) => DashboardPage()), MaterialPageRoute(builder: (context) => const AccueilPage()),
); );
}, },
child: const Text('OK'), child: const Text('OK'),
@ -386,46 +361,6 @@ Future<void> _loadPointsDeVente() async {
), ),
), ),
), ),
// Dans la méthode build, après le DropdownButton des rôles
const SizedBox(height: 16.0),
_isLoadingPointsDeVente
? const CircularProgressIndicator()
: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<int>(
value: _selectedPointDeVenteId,
hint: const Text('Sélectionner un point de vente'),
isExpanded: true,
onChanged: _isLoading
? null
: (int? newValue) {
setState(() {
_selectedPointDeVenteId = newValue;
});
},
items: _availablePointsDeVente
.map<DropdownMenuItem<int>>((Map<String, dynamic> point) {
return DropdownMenuItem<int>(
value: point['id'] as int,
child: Row(
children: [
const Icon(Icons.store, size: 20),
const SizedBox(width: 8),
Text(point['nom']),
],
),
);
}).toList(),
),
),
),
const SizedBox(height: 16.0),
const SizedBox(height: 24.0), const SizedBox(height: 24.0),
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,

View File

@ -3,7 +3,6 @@ import 'package:intl/intl.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import 'package:youmazgestion/Views/particles.dart' show ParticleBackground; import 'package:youmazgestion/Views/particles.dart' show ParticleBackground;
import 'package:youmazgestion/Views/produitsCard.dart'; import 'package:youmazgestion/Views/produitsCard.dart';
import 'Components/appDrawer.dart'; import 'Components/appDrawer.dart';
@ -11,7 +10,7 @@ import 'Components/app_bar.dart';
import 'Components/cartItem.dart'; import 'Components/cartItem.dart';
import 'Models/produit.dart'; import 'Models/produit.dart';
import 'Services/OrderDatabase.dart'; import 'Services/OrderDatabase.dart';
//import 'Services/productDatabase.dart'; import 'Services/productDatabase.dart';
import 'Views/ticketPage.dart'; import 'Views/ticketPage.dart';
import 'controller/userController.dart'; import 'controller/userController.dart';
import 'my_app.dart'; import 'my_app.dart';
@ -26,7 +25,7 @@ class AccueilPage extends StatefulWidget {
class _AccueilPageState extends State<AccueilPage> { class _AccueilPageState extends State<AccueilPage> {
final UserController userController = Get.put(UserController()); final UserController userController = Get.put(UserController());
final AppDatabase productDatabase = AppDatabase.instance; final ProductDatabase productDatabase = ProductDatabase();
late Future<Map<String, List<Product>>> productsFuture; late Future<Map<String, List<Product>>> productsFuture;
final OrderDatabase orderDatabase = OrderDatabase.instance; final OrderDatabase orderDatabase = OrderDatabase.instance;
final WorkDatabase workDatabase = WorkDatabase.instance; final WorkDatabase workDatabase = WorkDatabase.instance;

View File

@ -1,18 +1,17 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import 'package:youmazgestion/controller/userController.dart'; import 'package:youmazgestion/controller/userController.dart';
import '../Components/cartItem.dart'; import '../Components/cartItem.dart';
import '../Models/produit.dart'; import '../Models/produit.dart';
import '../Services/OrderDatabase.dart'; import '../Services/OrderDatabase.dart';
import '../Services/WorkDatabase.dart'; import '../Services/WorkDatabase.dart';
//import '../Services/productDatabase.dart'; import '../Services/productDatabase.dart';
import '../Views/ticketPage.dart'; import '../Views/ticketPage.dart';
import '../my_app.dart'; import '../my_app.dart';
class AccueilController extends GetxController { class AccueilController extends GetxController {
final UserController userController = Get.find(); final UserController userController = Get.find();
final AppDatabase productDatabase = AppDatabase.instance; final ProductDatabase productDatabase = ProductDatabase();
final Rx<Map<String, List<Product>>> productsFuture = Rx({}); // Observable final Rx<Map<String, List<Product>>> productsFuture = Rx({}); // Observable
final OrderDatabase orderDatabase = OrderDatabase.instance; final OrderDatabase orderDatabase = OrderDatabase.instance;
final WorkDatabase workDatabase = WorkDatabase.instance; final WorkDatabase workDatabase = WorkDatabase.instance;

View File

@ -1,8 +1,7 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:youmazgestion/Models/users.dart'; import 'package:youmazgestion/Models/users.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart'; import 'package:youmazgestion/Services/app_database.dart';
//import 'package:youmazgestion/Services/app_database.dart';
class UserController extends GetxController { class UserController extends GetxController {
final _username = ''.obs; final _username = ''.obs;
@ -12,8 +11,6 @@ class UserController extends GetxController {
final _lastname = ''.obs; final _lastname = ''.obs;
final _password = ''.obs; final _password = ''.obs;
final _userId = 0.obs; // Ajout de l'ID utilisateur final _userId = 0.obs; // Ajout de l'ID utilisateur
final _pointDeVenteId = 0.obs;
final _pointDeVenteDesignation = ''.obs;
String get username => _username.value; String get username => _username.value;
String get email => _email.value; String get email => _email.value;
@ -22,8 +19,6 @@ class UserController extends GetxController {
String get lastname => _lastname.value; String get lastname => _lastname.value;
String get password => _password.value; String get password => _password.value;
int get userId => _userId.value; int get userId => _userId.value;
int get pointDeVenteId => _pointDeVenteId.value;
String get pointDeVenteDesignation => _pointDeVenteDesignation.value;
@override @override
void onInit() { void onInit() {
@ -32,64 +27,48 @@ class UserController extends GetxController {
} }
// CORRECTION : Charger les données complètes depuis SharedPreferences ET la base de données // CORRECTION : Charger les données complètes depuis SharedPreferences ET la base de données
Future<void> loadUserData() async { Future<void> loadUserData() async {
try { try {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final storedUsername = prefs.getString('username') ?? ''; final storedUsername = prefs.getString('username') ?? '';
final storedRole = prefs.getString('role') ?? ''; final storedRole = prefs.getString('role') ?? '';
final storedUserId = prefs.getInt('user_id') ?? 0; final storedUserId = prefs.getInt('user_id') ?? 0;
final storedPointDeVenteId = prefs.getInt('point_de_vente_id') ?? 0;
final storedPointDeVenteDesignation = prefs.getString('point_de_vente_designation') ?? '';
if (storedUsername.isNotEmpty) { if (storedUsername.isNotEmpty) {
try { try {
Users user = await AppDatabase.instance.getUser(storedUsername); // Récupérer les données complètes depuis la base de données
Users user = await AppDatabase.instance.getUser(storedUsername);
_username.value = user.username; // Mettre à jour TOUTES les données
_email.value = user.email; _username.value = user.username;
_name.value = user.name; _email.value = user.email;
_lastname.value = user.lastName; _name.value = user.name;
_password.value = user.password; _lastname.value = user.lastName;
_role.value = storedRole; _password.value = user.password;
_userId.value = storedUserId; _role.value = storedRole; // Récupéré depuis SharedPreferences
_pointDeVenteId.value = storedPointDeVenteId; _userId.value = storedUserId; // Récupéré depuis SharedPreferences
_pointDeVenteDesignation.value = storedPointDeVenteDesignation;
// Si la désignation n'est pas sauvegardée, on peut la récupérer print("✅ Données chargées depuis la DB - Username: ${_username.value}");
if (_pointDeVenteDesignation.value.isEmpty && _pointDeVenteId.value > 0) { print("✅ Name: ${_name.value}, Email: ${_email.value}");
await loadPointDeVenteDesignation(); print("✅ Role: ${_role.value}, UserID: ${_userId.value}");
} catch (dbError) {
print('❌ Erreur DB, chargement depuis SharedPreferences uniquement: $dbError');
// Fallback : charger depuis SharedPreferences uniquement
_username.value = storedUsername;
_email.value = prefs.getString('email') ?? '';
_role.value = storedRole;
_name.value = prefs.getString('name') ?? '';
_lastname.value = prefs.getString('lastname') ?? '';
_userId.value = storedUserId;
} }
} else {
} catch (dbError) { print("❌ Aucun utilisateur stocké trouvé");
// Fallback
_username.value = storedUsername;
_email.value = prefs.getString('email') ?? '';
_role.value = storedRole;
_name.value = prefs.getString('name') ?? '';
_lastname.value = prefs.getString('lastname') ?? '';
_userId.value = storedUserId;
_pointDeVenteId.value = storedPointDeVenteId;
_pointDeVenteDesignation.value = storedPointDeVenteDesignation;
} }
} catch (e) {
print('❌ Erreur lors du chargement des données utilisateur: $e');
} }
} catch (e) {
print('❌ Erreur lors du chargement des données utilisateur: $e');
} }
}
Future<void> loadPointDeVenteDesignation() async {
if (_pointDeVenteId.value <= 0) return;
try {
final pointDeVente = await AppDatabase.instance.getPointDeVenteById(_pointDeVenteId.value);
if (pointDeVente != null) {
_pointDeVenteDesignation.value = pointDeVente['designation'] as String;
await saveUserData(); // Sauvegarder la désignation
}
} catch (e) {
print('❌ Erreur lors du chargement de la désignation du point de vente: $e');
}
}
// NOUVELLE MÉTHODE : Mise à jour complète avec Users + credentials // NOUVELLE MÉTHODE : Mise à jour complète avec Users + credentials
void setUserWithCredentials(Users user, String role, int userId) { void setUserWithCredentials(Users user, String role, int userId) {
@ -100,7 +79,6 @@ Future<void> loadPointDeVenteDesignation() async {
_lastname.value = user.lastName; _lastname.value = user.lastName;
_password.value = user.password; _password.value = user.password;
_userId.value = userId; // ID depuis les credentials _userId.value = userId; // ID depuis les credentials
_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}");
@ -133,52 +111,49 @@ Future<void> loadPointDeVenteDesignation() async {
// CORRECTION : Sauvegarder TOUTES les données importantes // CORRECTION : Sauvegarder TOUTES les données importantes
Future<void> saveUserData() async { Future<void> saveUserData() async {
try { try {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
await prefs.setString('username', _username.value); await prefs.setString('username', _username.value);
await prefs.setString('email', _email.value); await prefs.setString('email', _email.value);
await prefs.setString('role', _role.value); await prefs.setString('role', _role.value);
await prefs.setString('name', _name.value); await prefs.setString('name', _name.value);
await prefs.setString('lastname', _lastname.value); await prefs.setString('lastname', _lastname.value);
await prefs.setInt('user_id', _userId.value); await prefs.setInt('user_id', _userId.value); // Sauvegarder l'ID
await prefs.setInt('point_de_vente_id', _pointDeVenteId.value);
await prefs.setString('point_de_vente_designation', _pointDeVenteDesignation.value);
print("✅ Données sauvegardées avec succès dans SharedPreferences"); print("✅ Données sauvegardées avec succès dans SharedPreferences");
} catch (e) { } catch (e) {
print('❌ Erreur lors de la sauvegarde des données utilisateur: $e'); print('❌ Erreur lors de la sauvegarde des données utilisateur: $e');
}
} }
}
// CORRECTION : Vider TOUTES les données (SharedPreferences + Observables) // CORRECTION : Vider TOUTES les données (SharedPreferences + Observables)
Future<void> clearUserData() async { Future<void> clearUserData() async {
try { try {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
await prefs.remove('username'); // Vider SharedPreferences
await prefs.remove('email'); await prefs.remove('username');
await prefs.remove('role'); await prefs.remove('email');
await prefs.remove('name'); await prefs.remove('role');
await prefs.remove('lastname'); await prefs.remove('name');
await prefs.remove('user_id'); await prefs.remove('lastname');
await prefs.remove('point_de_vente_id'); await prefs.remove('user_id'); // Supprimer l'ID aussi
await prefs.remove('point_de_vente_designation');
_username.value = ''; // Vider les variables observables
_email.value = ''; _username.value = '';
_role.value = ''; _email.value = '';
_name.value = ''; _role.value = '';
_lastname.value = ''; _name.value = '';
_password.value = ''; _lastname.value = '';
_userId.value = 0; _password.value = '';
_pointDeVenteId.value = 0; _userId.value = 0; // Réinitialiser l'ID
_pointDeVenteDesignation.value = '';
} catch (e) { print("✅ Toutes les données utilisateur ont été effacées");
print('❌ Erreur lors de l\'effacement des données utilisateur: $e'); } catch (e) {
print('❌ Erreur lors de l\'effacement des données utilisateur: $e');
}
} }
}
// MÉTHODE UTILITAIRE : Vérifier si un utilisateur est connecté // MÉTHODE UTILITAIRE : Vérifier si un utilisateur est connecté
bool get isLoggedIn => _username.value.isNotEmpty && _userId.value > 0; bool get isLoggedIn => _username.value.isNotEmpty && _userId.value > 0;
@ -216,16 +191,14 @@ Future<void> clearUserData() async {
// MÉTHODE DEBUG : Afficher l'état actuel // MÉTHODE DEBUG : Afficher l'état actuel
void debugPrintUserState() { void debugPrintUserState() {
print("=== ÉTAT UTILISATEUR ==="); print("=== ÉTAT UTILISATEUR ===");
print("Username: ${_username.value}"); print("Username: ${_username.value}");
print("Name: ${_name.value}"); print("Name: ${_name.value}");
print("Lastname: ${_lastname.value}"); print("Lastname: ${_lastname.value}");
print("Email: ${_email.value}"); print("Email: ${_email.value}");
print("Role: ${_role.value}"); print("Role: ${_role.value}");
print("UserID: ${_userId.value}"); print("UserID: ${_userId.value}");
print("PointDeVenteID: ${_pointDeVenteId.value}"); print("IsLoggedIn: $isLoggedIn");
print("PointDeVente: ${_pointDeVenteDesignation.value}"); print("========================");
print("IsLoggedIn: $isLoggedIn"); }
print("========================");
}
} }

View File

@ -1,9 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
//import 'package:youmazgestion/Services/app_database.dart'; import 'package:youmazgestion/Services/app_database.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import 'package:youmazgestion/controller/userController.dart'; import 'package:youmazgestion/controller/userController.dart';
//import 'Services/productDatabase.dart'; import 'Services/productDatabase.dart';
import 'my_app.dart'; import 'my_app.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
@ -12,15 +11,14 @@ void main() async {
try { try {
// Initialiser les bases de données une seule fois // Initialiser les bases de données une seule fois
// await AppDatabase.instance.deleteDatabaseFile(); // await AppDatabase.instance.deleteDatabaseFile();
// await ProductDatabase.instance.deleteDatabaseFile(); // await ProductDatabase.instance.deleteDatabaseFile();
// await ProductDatabase.instance.initDatabase(); await ProductDatabase.instance.initDatabase();
await AppDatabase.instance.initDatabase(); await AppDatabase.instance.initDatabase();
// Afficher les informations de la base (pour debug) // Afficher les informations de la base (pour debug)
// await AppDatabase.instance.printDatabaseInfo(); await AppDatabase.instance.printDatabaseInfo();
Get.put( Get.put(
UserController()); // Ajoute ce code AVANT tout accès au UserController UserController()); // Ajoute ce code AVANT tout accès au UserController
setupLogger(); setupLogger();

View File

@ -7,7 +7,6 @@ import Foundation
import file_picker import file_picker
import file_selector_macos import file_selector_macos
import mobile_scanner
import open_file_mac import open_file_mac
import path_provider_foundation import path_provider_foundation
import shared_preferences_foundation import shared_preferences_foundation
@ -17,7 +16,6 @@ import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin")) OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))

View File

@ -241,14 +241,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.3+4" version: "0.9.3+4"
fl_chart:
dependency: "direct main"
description:
name: fl_chart
sha256: "5a74434cc83bf64346efb562f1a06eefaf1bcb530dc3d96a104f631a1eff8d79"
url: "https://pub.dev"
source: hosted
version: "0.65.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -616,14 +608,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.6" version: "1.0.6"
mobile_scanner:
dependency: "direct main"
description:
name: mobile_scanner
sha256: d234581c090526676fd8fab4ada92f35c6746e3fb4f05a399665d75a399fb760
url: "https://pub.dev"
source: hosted
version: "5.2.3"
msix: msix:
dependency: "direct main" dependency: "direct main"
description: description:
@ -640,14 +624,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0" version: "1.0.0"
numbers_to_letters:
dependency: "direct main"
description:
name: numbers_to_letters
sha256: "70c7ed2f04c1982a299e753101fbc2d52ed5b39a2b3dd2a9c07ba131e9c0948e"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
open_file: open_file:
dependency: "direct main" dependency: "direct main"
description: description:
@ -1065,18 +1041,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: syncfusion_flutter_charts name: syncfusion_flutter_charts
sha256: "0222ac9d8cb6c671f014effe9bd5c0aef35eadb16471355345ba87cc0ac007b3" sha256: bdb7cc5814ceb187793cea587f4a5946afcffd96726b219cee79df8460f44b7b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "20.4.54" version: "21.2.4"
syncfusion_flutter_core: syncfusion_flutter_core:
dependency: transitive dependency: transitive
description: description:
name: syncfusion_flutter_core name: syncfusion_flutter_core
sha256: "3979f0b1c5a97422cadae52d476c21fa3e0fb671ef51de6cae1d646d8b99fe1f" sha256: "8db8f55c77f56968681447d3837c10f27a9e861e238a898fda116c7531def979"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "20.4.54" version: "21.2.10"
synchronized: synchronized:
dependency: transitive dependency: transitive
description: description:

View File

@ -50,7 +50,7 @@ dependencies:
logging: ^1.2.0 logging: ^1.2.0
msix: ^3.7.0 msix: ^3.7.0
flutter_charts: ^0.5.1 flutter_charts: ^0.5.1
syncfusion_flutter_charts: ^20.4.48 syncfusion_flutter_charts: ^21.2.4
shelf: ^1.4.1 shelf: ^1.4.1
shelf_router: ^1.1.4 shelf_router: ^1.1.4
pdf: ^3.8.4 pdf: ^3.8.4
@ -62,9 +62,7 @@ dependencies:
path_provider: ^2.0.15 path_provider: ^2.0.15
shared_preferences: ^2.2.2 shared_preferences: ^2.2.2
excel: ^2.0.1 excel: ^2.0.1
mobile_scanner: ^5.0.0 # ou la version la plus récente
fl_chart: ^0.65.0 # Version la plus récente au moment de cette répons
numbers_to_letters: ^1.0.0
@ -103,11 +101,6 @@ flutter:
- assets/database/usersdb.db - assets/database/usersdb.db
- assets/database/work.db - assets/database/work.db
- assets/database/roles.db - assets/database/roles.db
- assets/airtel_money.png
- assets/mvola.jpg
- assets/Orange_money.png
- assets/fa-solid-900.ttf
- assets/fonts/Roboto-Italic.ttf
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware # https://flutter.dev/assets-and-images/#resolution-aware