You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1151 lines
40 KiB

import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:youmazgestion/controller/userController.dart';
// Models
import '../Models/users.dart';
import '../Models/role.dart';
import '../Models/Permission.dart';
import '../Models/client.dart';
import '../Models/produit.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();
await _insertDefaultClients();
await _insertDefaultCommandes();
await insertDefaultPointsDeVente(); // Ajouté ici
}
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("Aucune DB pré-chargée trouvée, création d'une nouvelle");
}
}
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();
// --- UTILISATEURS / ROLES / PERMISSIONS ---
if (!tableNames.contains('roles')) {
await db.execute('''CREATE TABLE roles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
designation TEXT NOT NULL UNIQUE
)''');
}
if (!tableNames.contains('permissions')) {
await db.execute('''CREATE TABLE permissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE
)''');
}
if (!tableNames.contains('menu')) {
await db.execute('''CREATE TABLE menu (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
route TEXT NOT NULL
)''');
}
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),
FOREIGN KEY (permission_id) REFERENCES permissions(id)
)''');
}
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),
FOREIGN KEY (menu_id) REFERENCES menu(id),
FOREIGN KEY (permission_id) REFERENCES permissions(id)
)''');
}
// --- POINTS DE VENTE ---
if (!tableNames.contains('points_de_vente')) {
await db.execute('''CREATE TABLE points_de_vente (
id INTEGER PRIMARY KEY AUTOINCREMENT,
designation TEXT NOT NULL UNIQUE
)''');
}
// --- UTILISATEURS ---
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,
point_de_vente_id INTEGER,
FOREIGN KEY (role_id) REFERENCES roles(id),
FOREIGN KEY (point_de_vente_id) REFERENCES points_de_vente(id)
)''');
} else {
// Si la table existe déjà, ajouter la colonne si elle n'existe pas
try {
await db.execute('ALTER TABLE users ADD COLUMN point_de_vente_id INTEGER REFERENCES points_de_vente(id)');
} catch (e) {
print("La colonne point_de_vente_id existe déjà dans la table users");
}
}
// --- PRODUITS ---
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,
point_de_vente_id INTEGER,
FOREIGN KEY (point_de_vente_id) REFERENCES points_de_vente(id)
)''');
} else {
// Si la table existe déjà, ajouter la colonne si elle n'existe pas
try {
await db.execute('ALTER TABLE products ADD COLUMN point_de_vente_id INTEGER REFERENCES points_de_vente(id)');
} catch (e) {
print("La colonne point_de_vente_id existe déjà dans la table products");
}
}
// --- 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
)''');
}
// --- 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,
commandeurId INTEGER,
validateurId INTEGER,
FOREIGN KEY (commandeurId) REFERENCES users(id),
FOREIGN KEY (validateurId) REFERENCES users(id),
FOREIGN KEY (clientId) REFERENCES clients(id)
)''');
}
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),
FOREIGN KEY (produitId) REFERENCES products(id)
)''');
}
// Indexes
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)');
}
// --- MÉTHODES UTILISATEURS / ROLES / PERMISSIONS ---
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");
}
}
}/* Copier depuis ton code */ }
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);
} /* Copier depuis ton code */ }
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'});
int commercialRoleId = await db.insert('roles', {'designation': 'commercial'});
int caisseRoleId = await db.insert('roles', {'designation': 'caisse'});
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);
}/* Copier depuis ton code */ }
Future<void> insertDefaultPointsDeVente() async {
final db = await database;
final existing = await db.query('points_de_vente');
if (existing.isEmpty) {
final defaultPoints = [
{'designation': 'Behoririka'},
{'designation': 'Antanimena'},
{'designation': 'Analakely'},
{'designation': 'Andravoahangy'},
{'designation': 'Anosy'},
];
for (var point in defaultPoints) {
await db.insert('points_de_vente', point);
}
print("Points de vente par défaut insérés");
}
}
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à");
}/* Copier depuis ton code */ }
// CRUD Users
// Dans la méthode createUser
Future<int> createUser(Users user) async {
final db = await database;
return await db.insert('users', user.toMap());
}
// Dans la méthode updateUser
Future<int> updateUser(Users user) async {
final db = await database;
return await db.update(
'users',
user.toMap(),
where: 'id = ?',
whereArgs: [user.id]
);
}
Future<int> deleteUser(int id) async { final db = await database;
return await db.delete('users', where: 'id = ?', whereArgs: [id]);
/* Copier depuis ton code */ }
// Future<int> updateUser(Users user) async { final db = await database;
// return await db.update('users', user.toMap(), where: 'id = ?', whereArgs: [user.id]);
// /* Copier depuis ton code */ }
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(); /* Copier depuis ton code */ }
// CRUD Roles
Future<int> createRole(Role role) async { final db = await database;
return await db.insert('roles', role.toMap());/* Copier depuis ton code */ }
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]));
/* Copier depuis ton code */ }
Future<int> updateRole(Role role) async { final db = await database;
return await db.update(
'roles',
role.toMap(),
where: 'id = ?',
whereArgs: [role.id],
);/* Copier depuis ton code */ }
Future<int> deleteRole(int? id) async { final db = await database;
return await db.delete(
'roles',
where: 'id = ?',
whereArgs: [id],
);/* Copier depuis ton code */ }
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();
}
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<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> 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],
);
}
Future<Users?> getUserById(int id) 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.id = ?
''', [id]);
if (result.isNotEmpty) {
return Users.fromMap(result.first);
}
return null;
}
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<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("=========================================");
}
// CRUD Permissions
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();
/* Copier depuis ton code */ }
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();
/* Copier depuis ton code */ }
// Gestion des accès
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; /* Copier depuis ton code */ }
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');
} /* Copier depuis ton code */ }
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;
}/* Copier depuis ton code */ }
// --- MÉTHODES PRODUITS / CLIENTS / COMMANDES ---
// CRUD Produits
// Dans la méthode createProduct
Future<int> createProduct(Product product) async {
final db = await database;
// Récupérer le point de vente de l'utilisateur connecté
final userCtrl = Get.find<UserController>();
final currentPointDeVenteId = userCtrl.pointDeVenteId;
// Si le produit n’a pas de point_de_vente_id, on lui assigne celui de l'utilisateur connecté
final Map<String, dynamic> productData = product.toMap();
if (currentPointDeVenteId > 0 && (product.pointDeVenteId == null || product.pointDeVenteId == 0)) {
productData['point_de_vente_id'] = currentPointDeVenteId;
}
return await db.insert('products', productData);
}
// Dans la méthode updateProduct
Future<int> updateProduct(Product product) async {
final db = await database;
return await db.update(
'products',
product.toMap(),
where: 'id = ?',
whereArgs: [product.id],
);
}
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]);
});/* Copier depuis ton code */ }
// Future<int> updateProduct(Product product) async { final db = await database;
// return await db.update(
// 'products',
// product.toMap(),
// where: 'id = ?',
// whereArgs: [product.id],
// );/* Copier depuis ton code */ }
Future<int> deleteProduct(int? id) async { final db = await database;
return await db.delete(
'products',
where: 'id = ?',
whereArgs: [id],
);/* Copier depuis ton code */ }
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);
/* Copier depuis ton code */ }
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]);
});/* Copier depuis ton code */ }
// CRUD Clients
Future<int> createClient(Client client) async { final db = await database;
return await db.insert('clients', client.toMap());/* Copier depuis ton code */ }
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]);
});/* Copier depuis ton code */ }
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;/* Copier depuis ton code */ }
Future<int> updateClient(Client client) async { final db = await database;
return await db.update(
'clients',
client.toMap(),
where: 'id = ?',
whereArgs: [client.id],
);/* Copier depuis ton code */ }
Future<int> deleteClient(int id) async { final db = await database;
// Soft delete
return await db.update(
'clients',
{'actif': 0},
where: 'id = ?',
whereArgs: [id],
); /* Copier depuis ton code */ }
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]);
});/* Copier depuis ton code */ }
Future<List<Users>> getCommercialUsers() 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 roles.designation = 'commercial'
ORDER BY users.id ASC
''');
return result.map((json) => Users.fromMap(json)).toList();
}
// Dans AppDatabase (stock_managementDatabase.dart)
// Créer une commande
Future<int> createCommande(Commande commande) async {
final db = await database;
return await db.insert('commandes', commande.toMap());
}
// Récupérer toutes les commandes avec les infos client
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) => Commande.fromMap(maps[i]));
}
// Récupérer une commande par son ID
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;
}
// Mettre à jour une commande
Future<int> updateCommande(Commande commande) async {
final db = await database;
return await db.update(
'commandes',
commande.toMap(),
where: 'id = ?',
whereArgs: [commande.id],
);
}
// Mettre à jour seulement le statut
Future<int> updateStatutCommande(int commandeId, StatutCommande statut) async {
final db = await database;
return await db.update(
'commandes',
{'statut': statut.index},
where: 'id = ?',
whereArgs: [commandeId],
);
}
// Supprimer une commande
Future<int> deleteCommande(int id) async {
final db = await database;
return await db.delete(
'commandes',
where: 'id = ?',
whereArgs: [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;
}
// Détails commandes
// Créer un détail de commande
Future<int> createDetailCommande(DetailCommande detail) async {
final db = await database;
return await db.insert('details_commandes', detail.toMap());
}
// Récupérer les détails d'une commande
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) => DetailCommande.fromMap(maps[i]));
}
// Transactions complexes
Future<int> createCommandeComplete(Client client, Commande commande, List<DetailCommande> details) async {
final db = await database;
return await db.transaction((txn) async {
// 1. Créer le client
final clientId = await txn.insert('clients', client.toMap());
// 2. Créer la commande avec le bon clientId
final commandeMap = commande.toMap();
commandeMap['clientId'] = clientId;
final commandeId = await txn.insert('commandes', commandeMap);
// 3. Créer les détails de commande
for (final detail in details) {
final detailMap = detail.toMap();
detailMap['commandeId'] = commandeId;
await txn.insert('details_commandes', detailMap);
// 4. Mettre à jour le stock
await txn.rawUpdate(
'UPDATE products SET stock = stock - ? WHERE id = ?',
[detail.quantite, detail.produitId],
);
}
return commandeId;
});
}
// Récupérer les commandes d'un client
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) => Commande.fromMap(maps[i]));
}
// Récupérer les commandes par statut
Future<List<Commande>> getCommandesByStatut(StatutCommande statut) 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.statut = ?
ORDER BY c.dateCommande DESC
''', [statut.index]);
return List.generate(maps.length, (i) => Commande.fromMap(maps[i]));
}
Future<int> updateValidateurCommande(int commandeId, int validateurId) async {
final db = await database;
return await db.update(
'commandes',
{
'validateurId': validateurId,
'statut': StatutCommande.confirmee.index,
},
where: 'id = ?',
whereArgs: [commandeId],
);
}
Future<int> updateStock(int productId, int newStock) async {
final db = await database;
return await db.update(
'products',
{'stock': newStock},
where: 'id = ?',
whereArgs: [productId],
);
}
// 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");
} /* Copier depuis ton code */ }
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");
}
}/* Copier depuis ton code */ }
// 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,
};/* Copier depuis ton code */ }
// Fermeture
Future<void> close() async {
if (_database.isOpen) {
await _database.close();
}
}
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");
}
}
// 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> _addMissingMenus(Database db) async {
final menusToAdd = [
{'name': 'Nouvelle commande', 'route': '/nouvelle-commande'},
{'name': 'Gérer les commandes', 'route': '/gerer-commandes'},
];
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<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;
}
// Pour réinitialiser la base (débogage)
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 product supprimée");
}/* Copier depuis ton code */ }
// CRUD Points de vente
Future<int> createPointDeVente(String designation) async {
final db = await database;
return await db.insert('points_de_vente', {
'designation': designation
},
conflictAlgorithm: ConflictAlgorithm.ignore
);
}
Future<List<Map<String, dynamic>>> getPointsDeVente() async {
final db = await database;
return await db.query('points_de_vente', orderBy: 'designation ASC');
}
Future<int> updatePointDeVente(int id, String newDesignation) async {
final db = await database;
return await db.update(
'points_de_vente',
{'designation': newDesignation},
where: 'id = ?',
whereArgs: [id],
);
}
Future<int> deletePointDeVente(int id) async {
final db = await database;
return await db.delete(
'points_de_vente',
where: 'id = ?',
whereArgs: [id],
);
}
// Dans AppDatabase
Future<Map<String, int>> getProductCountByCategory() async {
final db = await database;
final result = await db.rawQuery('''
SELECT category, COUNT(*) as count
FROM products
GROUP BY category
ORDER BY count DESC
''');
return Map.fromEntries(result.map((e) =>
MapEntry(e['category'] as String, e['count'] as int)));
}
Future<Map<String, dynamic>?> getPointDeVenteById(int id) async {
final db = await database;
final result = await db.query(
'points_de_vente',
where: 'id = ?',
whereArgs: [id],
);
return result.isNotEmpty ? result.first : null;
}
}