diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 064f6389..728d45b5 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -166,6 +166,15 @@ $routes->group('', ['filter' => 'auth'], function ($routes) { /** * route for the products */ + $routes->get('/product', function() { + return redirect()->to('/products'); + }); + + // Route pour /product/(:any) qui redirige vers /products/(:any) + $routes->get('/product/(:any)', function($segment) { + return redirect()->to('/products/'.$segment); + }); + $routes->group('/products', function ($routes) { $routes->get('/', [ProductCOntroller::class, 'index']); $routes->get('fetchProductData', [ProductCOntroller::class, 'fetchProductData']); @@ -174,11 +183,11 @@ $routes->group('', ['filter' => 'auth'], function ($routes) { $routes->get('update/(:num)', [ProductCOntroller::class, 'update']); $routes->post('update/(:num)', [ProductCOntroller::class, 'update']); $routes->post('remove', [ProductCOntroller::class, 'remove']); + $routes->get('generateqrcode/(:num)', [QrCodeCOntroller::class, 'generate']); $routes->post('assign_store', [ProductCOntroller::class, 'assign_store']); $routes->post('createByExcel', [ProductCOntroller::class, 'createByExcel']); $routes->post('checkProductAvailability', [ProductCOntroller::class, 'checkProductAvailability']); }); - /** * route for the orders @@ -331,6 +340,8 @@ $routes->group('/avances', function ($routes) { // Route CRON (optionnel) $routes->get('checkDeadlineAlerts', [AvanceController::class, 'checkDeadlineAlerts']); + + }); // historique diff --git a/app/Controllers/Auth.php b/app/Controllers/Auth.php index 982004f5..17117f3a 100644 --- a/app/Controllers/Auth.php +++ b/app/Controllers/Auth.php @@ -46,32 +46,46 @@ class Auth extends AdminController return $file ? $file->getErrorString() : 'No file was uploaded.'; } - /** - * function used to login - * @return \CodeIgniter\HTTP\RedirectResponse - */ - public function loginPost() - { - $email = $this->request->getPost('email'); - $password = $this->request->getPost('password'); - - // Load the model and attempt login - $userModel = new Users(); - - $user = $userModel->attempt($email, $password); - - if ($user) { - // Set user session - session()->set('user', $user); - - // Redirect to dashboard - return redirect()->to('/'); - } - - // If login fails, redirect back with an error - return redirect()->to('/login')->with('error', 'Invalid email or password.'); +/** + * function used to login + * @return \CodeIgniter\HTTP\RedirectResponse + */ +public function loginPost() +{ + $email = $this->request->getPost('email'); + $password = $this->request->getPost('password'); + + // Load the model and attempt login + $userModel = new Users(); + $user = $userModel->attempt($email, $password); + + if ($user) { + // Ajouter le nom complet et le rôle dans le tableau $user + $user['username'] = trim(($user['firstname'] ?? '') . ' ' . ($user['lastname'] ?? '')); + $user['role'] = $user['group_name'] ?? 'Aucun groupe'; + + // Set user session (garde la structure originale qui fonctionne) + session()->set('user', $user); + + // Ajouter aussi les clés individuelles pour le header + session()->set([ + 'user_id' => $user['id'], + 'username' => $user['username'], + 'role' => $user['role'], + 'email' => $user['email'] ?? '', + 'group_id' => $user['group_id'] ?? null, + 'store_id' => $user['store_id'] ?? null, + 'permission' => $user['permission'] ?? '', + 'logged_in' => true + ]); + + // Redirect to dashboard + return redirect()->to('/'); } + // If login fails, redirect back with an error + return redirect()->to('/login')->with('error', 'Invalid email or password.'); +} public function logout() { session()->destroy(); diff --git a/app/Controllers/AvanceController.php b/app/Controllers/AvanceController.php index 7579badd..2e886ede 100644 --- a/app/Controllers/AvanceController.php +++ b/app/Controllers/AvanceController.php @@ -563,6 +563,7 @@ public function fetchExpiredAvance() $type_avance = $this->request->getPost('type_avance_edit'); + // ✅ VALIDATION $validation = \Config\Services::validation(); $baseRules = [ @@ -602,11 +603,11 @@ public function fetchExpiredAvance() ]); } + // ✅ VÉRIFICATIONS PERMISSIONS $isAdmin = $this->isAdmin($users); $isOwner = $users['id'] === $existingAvance['user_id']; $isCaissier = $this->isCaissier($users); - // ✅ MODIFIÉ : Le caissier peut maintenant modifier toutes les avances if (!$isAdmin && !$isOwner && !$isCaissier) { return $this->response->setJSON([ 'success' => false, @@ -614,6 +615,7 @@ public function fetchExpiredAvance() ]); } + // ✅ GESTION DEADLINE $current_deadline = $existingAvance['deadline']; if ($type_avance !== $existingAvance['type_avance']) { @@ -626,6 +628,7 @@ public function fetchExpiredAvance() $old_product_id = $existingAvance['product_id']; + // ✅ PRÉPARER LES DONNÉES $data = [ 'type_avance' => $type_avance, 'type_payment' => $this->request->getPost('type_payment_edit'), @@ -638,7 +641,8 @@ public function fetchExpiredAvance() 'avance_amount' => (float)$this->request->getPost('avance_amount_edit'), 'amount_due' => (float)$this->request->getPost('amount_due_edit') ]; - + + // ✅ GESTION PRODUIT SELON TYPE if ($type_avance === 'mere') { $data['product_name'] = $this->request->getPost('product_name_text_edit'); $data['product_id'] = null; @@ -651,22 +655,61 @@ public function fetchExpiredAvance() $data['commentaire'] = null; } - if ($Avance->updateAvance($avance_id, $data)) { + // ✅ MISE À JOUR (qui déclenchera automatiquement la conversion si nécessaire) + $updateResult = $Avance->updateAvance($avance_id, $data); + + if ($updateResult) { + // ✅ GESTION DES PRODUITS if ($type_avance === 'terre') { + // Libérer l'ancien produit si changement if ($old_product_id && $old_product_id !== $new_product_id) { $Products->update($old_product_id, ['product_sold' => 0]); } + // Marquer le nouveau produit comme vendu if ($new_product_id) { $Products->update($new_product_id, ['product_sold' => 1]); } } else { + // Si passage de terre à mer, libérer le produit if ($old_product_id && $existingAvance['type_avance'] === 'terre') { $Products->update($old_product_id, ['product_sold' => 0]); } } - // ✅ Notification simplifiée + // ✅ VÉRIFIER SI CONVERSION AUTOMATIQUE + $updatedAvance = $Avance->find($avance_id); + + if ($updatedAvance && $updatedAvance['is_order'] == 1) { + // ✅ L'avance a été convertie automatiquement ! + + // Trouver l'ID de la commande créée + $db = \Config\Database::connect(); + $order = $db->table('orders') + ->select('id, bill_no') + ->where('customer_name', $updatedAvance['customer_name']) + ->where('customer_phone', $updatedAvance['customer_phone']) + ->where('source', 'Avance convertie') + ->orderBy('id', 'DESC') + ->limit(1) + ->get() + ->getRowArray(); + + if ($order) { + log_message('info', "✅ Avance {$avance_id} convertie automatiquement en commande {$order['id']}"); + + return $this->response->setJSON([ + 'success' => true, + 'messages' => '✅ Avance modifiée et convertie automatiquement en commande !', + 'converted' => true, + 'order_id' => $order['id'], + 'bill_no' => $order['bill_no'], + 'redirect_url' => site_url('orders/update/' . $order['id']) + ]); + } + } + + // ✅ NOTIFICATION (modification simple) $Notification->createNotification( 'Une avance a été modifiée', "Caissière", @@ -685,7 +728,7 @@ public function fetchExpiredAvance() 'messages' => 'Erreur lors de la modification de l\'avance' ]); } - + } catch (\Exception $e) { log_message('error', "Erreur modification avance: " . $e->getMessage()); return $this->response->setJSON([ @@ -694,7 +737,7 @@ public function fetchExpiredAvance() ]); } } - + public function removeAvance() { @@ -2131,7 +2174,7 @@ public function payAvance() ]); } - // ✅ Vérifier si déjà convertie + // Vérifier si déjà convertie if ($avance['is_order'] == 1) { return $this->response->setJSON([ 'success' => false, @@ -2139,59 +2182,68 @@ public function payAvance() ]); } - // ✅ Calcul nouveau montant dû + // Calcul nouveau montant dû $amount_due = max(0, (float)$avance['amount_due'] - $montant_paye); - // ✅ Mise à jour avance - $avanceModel->update($avance_id, [ + // ✅ Utiliser updateAvance() qui va automatiquement vérifier la conversion + $updateResult = $avanceModel->updateAvance($avance_id, [ 'avance_amount' => (float)$avance['avance_amount'] + $montant_paye, 'amount_due' => $amount_due, ]); + if (!$updateResult) { + return $this->response->setJSON([ + 'success' => false, + 'message' => 'Erreur lors de la mise à jour' + ]); + } + log_message('info', "💰 Paiement {$montant_paye} Ar sur avance {$avance_id} (Type: {$avance['type_avance']})"); - // ✅ CONVERSION si paiement complet - if ($amount_due <= 0) { + // ✅ Vérifier si l'avance a été convertie automatiquement + $updatedAvance = $avanceModel->find($avance_id); + + if ($updatedAvance && $updatedAvance['is_order'] == 1) { + // ✅ Conversion automatique effectuée ! - if ($avance['type_avance'] === 'terre') { - log_message('info', "🔄 Avance TERRE {$avance_id} complétée → Conversion en commande..."); - - $order_id = $avanceModel->convertToOrder($avance_id); - - if ($order_id) { - log_message('info', "✅ Conversion réussie → Commande {$order_id}"); - - return $this->response->setJSON([ - 'success' => true, - 'message' => '✅ Paiement effectué ! L\'avance a été convertie en commande.', - 'converted' => true, - 'type' => 'terre', - 'order_id' => $order_id, - 'redirect_url' => site_url('orders/update/' . $order_id) - ]); - } else { - log_message('error', "❌ Échec conversion avance {$avance_id}"); - - return $this->response->setJSON([ - 'success' => false, - 'message' => '⚠️ Paiement enregistré mais erreur lors de la conversion. Contactez l\'administrateur.' - ]); - } - - } else { - // ✅ Avance MER complète - log_message('info', "✅ Avance MER {$avance_id} complétée (pas de conversion)"); + // Trouver la commande + $db = \Config\Database::connect(); + $order = $db->table('orders') + ->select('id, bill_no') + ->where('customer_name', $updatedAvance['customer_name']) + ->where('customer_phone', $updatedAvance['customer_phone']) + ->where('source', 'Avance convertie') + ->orderBy('id', 'DESC') + ->limit(1) + ->get() + ->getRowArray(); + + if ($order) { + log_message('info', "✅ Avance {$avance_id} convertie automatiquement en commande {$order['id']} après paiement"); return $this->response->setJSON([ - 'success' => true, - 'message' => '✅ Paiement effectué ! L\'avance MER est maintenant complète.', - 'converted' => false, - 'type' => 'mere' + 'success' => true, + 'message' => '✅ Paiement effectué ! L\'avance a été automatiquement convertie en commande.', + 'converted' => true, + 'type' => 'terre', + 'order_id' => $order['id'], + 'bill_no' => $order['bill_no'], + 'redirect_url' => site_url('orders/update/' . $order['id']) ]); } } - // ✅ Paiement partiel + // Paiement partiel ou avance MER complète + if ($amount_due <= 0 && $avance['type_avance'] === 'mere') { + return $this->response->setJSON([ + 'success' => true, + 'message' => '✅ Paiement effectué ! L\'avance MER est maintenant complète.', + 'converted' => false, + 'type' => 'mere' + ]); + } + + // Paiement partiel return $this->response->setJSON([ 'success' => true, 'message' => '✅ Paiement partiel enregistré', @@ -2200,6 +2252,7 @@ public function payAvance() 'type' => $avance['type_avance'] ]); } + /** * ✅ Conversion manuelle (optionnel - pour forcer la conversion) */ diff --git a/app/Controllers/Dashboard.php b/app/Controllers/Dashboard.php index 42d37f73..933dd3de 100644 --- a/app/Controllers/Dashboard.php +++ b/app/Controllers/Dashboard.php @@ -21,7 +21,7 @@ class Dashboard extends AdminController public function index() { - // === 🔥 Récupérer l'utilisateur en premier === + // Récupérer l'utilisateur en premier $session = session(); $user_id = $session->get('user'); diff --git a/app/Controllers/GroupController.php b/app/Controllers/GroupController.php index c434b7de..f16d1aeb 100644 --- a/app/Controllers/GroupController.php +++ b/app/Controllers/GroupController.php @@ -138,37 +138,35 @@ class GroupController extends AdminController } public function delete(int $id = null) - { - $this->verifyRole('deleteGroup'); - $data['page_title'] = $this->pageTitle; - $groupsModel = new Groups(); +{ + $this->verifyRole('deleteGroup'); + $data['page_title'] = $this->pageTitle; + $groupsModel = new Groups(); - if ($id) { - if ($this->request->getMethod() === 'post' && $this->request->getPost('confirm')) { - // Check if the group exists in the user group - $check = $groupsModel->existInUserGroup($id); - if ($check) { - session()->setFlashdata('error', 'Group exists in the users'); - return redirect()->to('/groups'); - } else { - // Delete group - if ($groupsModel->delete($id)) { - session()->setFlashdata('success', 'Successfully removed'); - return redirect()->to('/groups'); - } else { - session()->setFlashdata('error', 'Error occurred!!'); - return redirect()->to("/groups/delete/{$id}"); - } - } - } else { - // Show confirmation view - $data['id'] = $id; - return $this->render_template('groups/delete', $data); - } + if (!$id) { + session()->setFlashdata('error', 'Invalid Group ID!'); + return redirect()->to('/groups'); + } + + // Vérifier si c'est une requête POST avec confirmation + if ($this->request->getMethod() === 'post' && $this->request->getPost('confirm')) { + + // Supprimer d'abord toutes les associations dans user_group + $groupsModel->removeUsersFromGroup($id); + + // Puis supprimer le groupe + if ($groupsModel->deleteGroup($id)) { + session()->setFlashdata('success', 'Rôle supprimé avec succès'); + return redirect()->to('/groups'); } else { - session()->setFlashdata('error', 'Invalid Group ID!'); + session()->setFlashdata('error', 'Une erreur est survenue lors de la suppression!'); return redirect()->to('/groups'); } } + + // Si ce n'est pas une requête POST, rediriger vers la liste + session()->setFlashdata('error', 'Action non autorisée!'); + return redirect()->to('/groups'); +} } \ No newline at end of file diff --git a/app/Controllers/MecanicienController.php b/app/Controllers/MecanicienController.php index bf3aeecd..bc7db875 100644 --- a/app/Controllers/MecanicienController.php +++ b/app/Controllers/MecanicienController.php @@ -84,7 +84,7 @@ class MecanicienController extends AdminController } $image = '' . $repa['name'] . ''; - $produit = $repa['sku']; + $produit = $repa['name'] . ' (' . $repa['sku'] . ')'; // Status display $status = strReparation($repa['reparation_statut']); $username = $repa['username']; @@ -313,13 +313,22 @@ class MecanicienController extends AdminController $session = session(); $users = $session->get('user'); + // ✅ RÉCUPÉRER LES PARAMÈTRES DE FILTRE + $startDate = $this->request->getGet('startDate'); + $endDate = $this->request->getGet('endDate'); + $pvente = $this->request->getGet('pvente'); + + // Log pour débogage + log_message('debug', 'Filtres Mécanicien reçus - startDate: ' . $startDate . ', endDate: ' . $endDate . ', pvente: ' . $pvente); + $data['id'] = $users['id']; - $reparation = $Mecanicien->getReparation($data['id']); - $result = ['data' => []]; - - // Iterate through the data - if($users['group_name'] == "SuperAdmin" || $users['group_name'] == "Direction"){ + // ✅ PASSER LES FILTRES AU MODÈLE + $reparation = $Mecanicien->getReparationWithFilters($data['id'], $startDate, $endDate, $pvente); + + $result = ['data' => []]; + + if($users['group_name'] == "SuperAdmin" || $users['group_name'] == "Direction" || $users['group_name'] == "DAF"){ foreach ($reparation as $key => $repa) { $image = '' . $repa['name'] . ''; $produit = esc($repa['name']); @@ -328,6 +337,7 @@ class MecanicienController extends AdminController $user_name = $first_name . ' ' . $last_name; $date_debut = date("d/m/Y", strtotime($repa['reparation_debut'])); $date_fin = date("d/m/Y", strtotime($repa['reparation_fin'])); + // Add the row data $result['data'][$key] = [ $user_name, @@ -338,17 +348,15 @@ class MecanicienController extends AdminController $date_fin, ]; } - return $this->response->setJSON($result); - } - else{ + } else { foreach ($reparation as $key => $repa) { $image = '' . $repa['name'] . ''; $produit = $repa['name']; - // Status display $username = $repa['username']; $date_debut = date("d/m/Y", strtotime($repa['reparation_debut'])); $date_fin = date("d/m/Y", strtotime($repa['reparation_fin'])); + // Add the row data $result['data'][$key] = [ $image, @@ -358,11 +366,8 @@ class MecanicienController extends AdminController $date_fin, ]; } - - // Return data in JSON format - return $this->response->setJSON($result); } - // Iterate through the data - + + return $this->response->setJSON($result); } } diff --git a/app/Controllers/ProductCOntroller.php b/app/Controllers/ProductCOntroller.php index 3727e403..6d57c867 100644 --- a/app/Controllers/ProductCOntroller.php +++ b/app/Controllers/ProductCOntroller.php @@ -247,7 +247,7 @@ class ProductCOntroller extends AdminController "Un nouveau Produit a été créé", "COMMERCIALE", $store_id1, - 'product/' + 'products/' ); return redirect()->to('/products'); diff --git a/app/Controllers/ReportController.php b/app/Controllers/ReportController.php index 9f890473..97edd024 100644 --- a/app/Controllers/ReportController.php +++ b/app/Controllers/ReportController.php @@ -261,9 +261,18 @@ class ReportController extends AdminController $session = session(); $users = $session->get('user'); - // Pour Direction et Conseil : afficher TOUTES les performances - if ($users['group_name'] === "DAF" || $users['group_name'] === "Direction" ||$users['group_name'] === "SuperAdmin" ) { - $orderPaid = $Orders->getPerformanceByOrders(); + // ✅ RÉCUPÉRER LES PARAMÈTRES DE FILTRE + $startDate = $this->request->getGet('startDate'); + $endDate = $this->request->getGet('endDate'); + $pvente = $this->request->getGet('pvente'); + + // ✅ CORRECTION : Bonne concaténation des chaînes + log_message('debug', 'Filtres Commercial reçus - startDate: ' . $startDate . ', endDate: ' . $endDate . ', pvente: ' . $pvente); + + // Pour Direction et Conseil : afficher TOUTES les performances AVEC FILTRES + if ($users['group_name'] === "DAF" || $users['group_name'] === "Direction" || $users['group_name'] === "SuperAdmin") { + // ✅ PASSER LES FILTRES AU MODÈLE - UNIQUEMENT POUR L'ADMIN + $orderPaid = $Orders->getPerformanceByOrders($startDate, $endDate, $pvente); foreach ($orderPaid as $key => $value) { // Déterminer le prix de vente réel $prix_vente_reel = (!empty($value['discount']) && $value['discount'] > 0) @@ -287,6 +296,7 @@ class ReportController extends AdminController return $this->response->setJSON($result); } + // ✅ POUR LES AUTRES RÔLES, GARDER L'ANCIENNE LOGIQUE SANS FILTRES // Pour Cheffe d'Agence : performances de son magasin if ($users['group_name'] === "Cheffe d'Agence") { $orderPaid = $Orders->getPerformanceByOrders1(); @@ -305,6 +315,7 @@ class ReportController extends AdminController } return $this->response->setJSON($result); } + if ($users['group_name'] === "Caissière") { $orderPaid = $Orders->getPerformanceByCaissier($users['id']); @@ -325,6 +336,7 @@ class ReportController extends AdminController return $this->response->setJSON($result); } + // Pour COMMERCIALE : uniquement ses propres ventes if ($users['group_name'] === "COMMERCIALE") { $orderPaid = $Orders->getPerformanceByOrders2(); diff --git a/app/Models/Avance.php b/app/Models/Avance.php index 790584e7..e0cad91d 100644 --- a/app/Models/Avance.php +++ b/app/Models/Avance.php @@ -40,6 +40,7 @@ class Avance extends Model { log_message('error', 'ID invalide pour la mise à jour du recouvrement : ' . $id); return false; } + try { if (!empty($data['type']) && !empty($data['avance_date'])) { if (strtolower($data['type']) === 'avance sur terre') { @@ -48,12 +49,77 @@ class Avance extends Model { $data['deadline'] = date('Y-m-d', strtotime($data['avance_date'] . ' +2 months')); } } - return $this->update($id, $data); + + // ✅ Mettre à jour l'avance + $updateResult = $this->update($id, $data); + + if (!$updateResult) { + return false; + } + + // ✅ AJOUT CRITIQUE : Vérifier automatiquement si conversion nécessaire + $this->autoCheckAndConvert($id); + + return true; + } catch (\Exception $e) { log_message('error', 'Erreur lors de la mise à jour de l\'avance : ' . $e->getMessage()); return false; } } + + private function autoCheckAndConvert(int $avance_id) +{ + try { + // Recharger l'avance fraîchement mise à jour + $avance = $this->find($avance_id); + + if (!$avance) { + log_message('warning', "⚠️ Avance {$avance_id} introuvable pour vérification auto"); + return false; + } + + // ✅ Conditions de conversion automatique + $shouldConvert = ( + $avance['type_avance'] === 'terre' && // C'est une avance sur terre + (float)$avance['amount_due'] <= 0.01 && // Montant dû = 0 (avec tolérance) + $avance['is_order'] == 0 && // Pas encore convertie + $avance['active'] == 1 // Encore active + ); + + if ($shouldConvert) { + log_message('info', "🔄 [AUTO-CHECK] Avance {$avance_id} complète détectée ! Conversion automatique..."); + + // ✅ Appeler la conversion + $order_id = $this->convertToOrder($avance_id); + + if ($order_id) { + log_message('info', "✅ [AUTO-CHECK] Conversion réussie → Commande {$order_id}"); + return $order_id; + } else { + log_message('error', "❌ [AUTO-CHECK] Échec conversion avance {$avance_id}"); + return false; + } + } else { + // Log pour débogage + $reason = ''; + if ($avance['type_avance'] !== 'terre') $reason .= 'type=' . $avance['type_avance'] . ' '; + if ((float)$avance['amount_due'] > 0.01) $reason .= 'reste=' . $avance['amount_due'] . ' '; + if ($avance['is_order'] == 1) $reason .= 'déjà_convertie '; + if ($avance['active'] == 0) $reason .= 'inactive '; + + if (!empty($reason)) { + log_message('info', "ℹ️ [AUTO-CHECK] Avance {$avance_id} non éligible pour conversion : {$reason}"); + } + } + + return false; + + } catch (\Exception $e) { + log_message('error', "❌ [AUTO-CHECK] Erreur vérification avance {$avance_id}: " . $e->getMessage()); + return false; + } +} public function getAllAvanceData(int $id=null) { $session = session(); diff --git a/app/Models/Groups.php b/app/Models/Groups.php index bf5db75a..f4b88d44 100644 --- a/app/Models/Groups.php +++ b/app/Models/Groups.php @@ -1,7 +1,5 @@ find($groupId); // Find by id + return $this->find($groupId); } - - return $this->where('id !=', 1)->findAll(); // Get all groups except where id = 1 + return $this->where('id !=', 1)->findAll(); } /** @@ -37,7 +33,7 @@ class Groups extends Model */ public function createGroup($data) { - return $this->insert($data); // Insert data into the groups table + return $this->insert($data); } /** @@ -48,17 +44,17 @@ class Groups extends Model */ public function editGroup($data, $id) { - return $this->update($id, $data); // Update group by id + return $this->update($id, $data); } /** * Delete group by id * @param mixed $id - * @return bool|\CodeIgniter\Database\BaseResult + * @return bool */ public function deleteGroup($id) { - return $this->delete($id); // Delete group by id + return $this->delete($id); } /** @@ -71,6 +67,25 @@ class Groups extends Model return $this->db->table('user_group')->where('group_id', $id)->countAllResults() > 0; } + /** + * Count users in a specific group + * @param mixed $id + * @return int + */ + public function countUsersInGroup($id) + { + return $this->db->table('user_group')->where('group_id', $id)->countAllResults(); + } + + /** + * Remove all users from a specific group + * @param mixed $id + * @return bool + */ + public function removeUsersFromGroup($id) + { + return $this->db->table('user_group')->where('group_id', $id)->delete(); + } /** * Get user group by userId * @param mixed $userId diff --git a/app/Models/Mecanicien.php b/app/Models/Mecanicien.php index e5889440..c6559e7f 100644 --- a/app/Models/Mecanicien.php +++ b/app/Models/Mecanicien.php @@ -75,5 +75,38 @@ class Mecanicien extends Model ->get() ->getRow(); } - + public function getReparationWithFilters(int $id = null, $startDate = null, $endDate = null, $pvente = null) + { + $session = session(); + $user = $session->get('user'); + + $builder = $this->select('reparations.reparation_id as reparationsID, reparations.user_id, reparations.reparation_statut, reparations.produit_id, reparations.reparation_observation, reparations.reparation_debut, reparations.reparation_fin, users.*, products.*, stores.name as store_name') + ->join('users', 'reparations.user_id = users.id') + ->join('products', 'reparations.produit_id = products.id') + ->join('stores', 'products.store_id = stores.id', 'left'); // ✅ JOINTURE AVEC MAGASINS + + // Filtre par utilisateur si pas admin + if ($user['group_name'] != "SuperAdmin" && $user['group_name'] != "Direction" && $user['group_name'] != "DAF") { + $builder->where('users.id', $id); + } + + // ✅ APPLIQUER LES FILTRES PAR DATE + if (!empty($startDate) && !empty($endDate)) { + $builder->where('DATE(reparations.reparation_debut) >=', $startDate); + $builder->where('DATE(reparations.reparation_debut) <=', $endDate); + } elseif (!empty($startDate)) { + $builder->where('DATE(reparations.reparation_debut) >=', $startDate); + } elseif (!empty($endDate)) { + $builder->where('DATE(reparations.reparation_debut) <=', $endDate); + } + + // ✅ FILTRE PAR POINT DE VENTE + if (!empty($pvente) && $pvente !== 'TOUS') { + $builder->where('stores.name', $pvente); + } + + $builder->orderBy('reparations.reparation_debut', 'DESC'); + + return $builder->findAll(); + } } diff --git a/app/Models/Orders.php b/app/Models/Orders.php index a8f4e0e5..cfddc929 100644 --- a/app/Models/Orders.php +++ b/app/Models/Orders.php @@ -110,8 +110,8 @@ class Orders extends Model 'orders.customer_phone', 'orders.customer_cin', 'orders.customer_address', - 'orders.customer_type', // ✅ DÉJÀ PRÉSENT - 'orders.source', // ✅ DÉJÀ PRÉSENT + 'orders.customer_type', + 'orders.source', 'orders.discount', 'orders.date_time', 'orders.gross_amount', @@ -367,12 +367,12 @@ class Orders extends Model $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF']); if($isAdmin) { - return $this->whereIn('paid_status', [1, 3]) // ← Ajoutez 3 ici + return $this->whereIn('paid_status', [1, 3]) // ✅ DÉJÀ BON ! ->orderBy('id', 'DESC') ->findAll(); } else { - return $this->whereIn('paid_status', [1, 3]) // ← Ajoutez 3 ici + return $this->whereIn('paid_status', [1, 3]) // ✅ DÉJÀ BON ! ->where('store_id', $users['store_id']) ->orderBy('id', 'DESC') ->findAll(); @@ -598,19 +598,34 @@ class Orders extends Model return $order; } - public function getPerformanceByOrders() + public function getPerformanceByOrders($startDate = null, $endDate = null, $pvente = null) { - $Performance = $this->db->table('orders') + $builder = $this->db->table('orders') ->select('orders.id as orderid, orders.net_amount, orders.date_time as datevente, orders.discount, products.price, products.sku, products.prix_vente, products.name as motoname, stores.id as store_id, users.firstname, users.lastname, users.email') ->join('stores', 'orders.store_id = stores.id') ->join('orders_item', 'orders.id = orders_item.order_id') ->join('products', 'products.id = orders_item.product_id') ->join('users', 'users.id = orders.user_id') - ->whereIn('orders.paid_status', [1, 3]) - ->get() - ->getResultArray(); - - return $Performance; + ->whereIn('orders.paid_status', [1, 3]); + + // ✅ AJOUT : FILTRES PAR DATE + if (!empty($startDate) && !empty($endDate)) { + $builder->where('DATE(orders.date_time) >=', $startDate); + $builder->where('DATE(orders.date_time) <=', $endDate); + } elseif (!empty($startDate)) { + $builder->where('DATE(orders.date_time) >=', $startDate); + } elseif (!empty($endDate)) { + $builder->where('DATE(orders.date_time) <=', $endDate); + } + + // ✅ AJOUT : FILTRE PAR POINT DE VENTE + if (!empty($pvente) && $pvente !== 'TOUS') { + $builder->where('stores.name', $pvente); + } + + $builder->orderBy('orders.date_time', 'DESC'); + + return $builder->get()->getResultArray(); } // for Adminan cheffe d'agence @@ -692,33 +707,46 @@ class Orders extends Model public function getUserPerformanceToday(string $date) { + $session = session(); + $currentUser = $session->get('user'); + $isAdmin = in_array($currentUser['group_name'], ['SuperAdmin', 'Direction', 'DAF']); + $users = $this->getUserList(); $results = []; foreach ($users as $user) { - $summary = $this->db->table('orders') + $builder = $this->db->table('orders') ->select('COUNT(id) AS total_user_order, SUM(net_amount) AS total_prix_vente') ->where('user_id', $user->user_id) ->where('DATE(date_time)', $date) - ->whereIn('paid_status', [1, 3]) - ->get() - ->getRow(); + ->whereIn('paid_status', [1, 3]); + + // ✅ Filtre par magasin si pas admin + if (!$isAdmin && !empty($currentUser['store_id']) && $currentUser['store_id'] != 0) { + $builder->where('store_id', $currentUser['store_id']); + } + + $summary = $builder->get()->getRow(); - $ids = $this->db->table('orders') + $idsBuilder = $this->db->table('orders') ->select('id') ->where('user_id', $user->user_id) ->where('DATE(date_time)', $date) - ->whereIn('paid_status', [1, 3]) - ->get() - ->getResult(); - + ->whereIn('paid_status', [1, 3]); + + // ✅ Filtre par magasin si pas admin + if (!$isAdmin && !empty($currentUser['store_id']) && $currentUser['store_id'] != 0) { + $idsBuilder->where('store_id', $currentUser['store_id']); + } + + $ids = $idsBuilder->get()->getResult(); $orderIds = array_map(fn($o) => $o->id, $ids); $results[] = [ 'user_id' => $user->user_id, 'full_name' => $user->full_name, - 'total_user_order' => $summary->total_user_order, - 'total_prix_vente' => $summary->total_prix_vente, + 'total_user_order' => $summary->total_user_order ?? 0, + 'total_prix_vente' => $summary->total_prix_vente ?? 0, 'order_ids' => $orderIds, ]; } @@ -728,6 +756,10 @@ class Orders extends Model public function getUserPerformanceByWeek(string $date = null) { + $session = session(); + $currentUser = $session->get('user'); + $isAdmin = in_array($currentUser['group_name'], ['SuperAdmin', 'Direction', 'DAF']); + $users = $this->getUserList(); $results = []; @@ -740,24 +772,33 @@ class Orders extends Model $endOfWeek = date('Y-m-d', strtotime('sunday this week', $timestamp)); foreach ($users as $user) { - $summary = $this->db->table('orders') + $builder = $this->db->table('orders') ->select('COUNT(id) AS total_user_order, SUM(net_amount) AS total_prix_vente') ->where('user_id', $user->user_id) ->where('DATE(date_time) >=', $startOfWeek) ->where('DATE(date_time) <=', $endOfWeek) - ->whereIn('paid_status', [1, 3]) - ->get() - ->getRow(); + ->whereIn('paid_status', [1, 3]); + + // ✅ Filtre par magasin si pas admin + if (!$isAdmin && !empty($currentUser['store_id']) && $currentUser['store_id'] != 0) { + $builder->where('store_id', $currentUser['store_id']); + } + + $summary = $builder->get()->getRow(); - $ids = $this->db->table('orders') + $idsBuilder = $this->db->table('orders') ->select('id') ->where('user_id', $user->user_id) ->where('DATE(date_time) >=', $startOfWeek) ->where('DATE(date_time) <=', $endOfWeek) - ->whereIn('paid_status', [1, 3]) - ->get() - ->getResult(); - + ->whereIn('paid_status', [1, 3]); + + // ✅ Filtre par magasin si pas admin + if (!$isAdmin && !empty($currentUser['store_id']) && $currentUser['store_id'] != 0) { + $idsBuilder->where('store_id', $currentUser['store_id']); + } + + $ids = $idsBuilder->get()->getResult(); $orderIds = array_map(fn($o) => $o->id, $ids); $results[] = [ @@ -771,7 +812,6 @@ class Orders extends Model return $results; } - public function checkMinimalPrice($product_id, $discount) { $fourchetteModel = new FourchettePrix(); // plus court car on a "use" @@ -787,6 +827,10 @@ public function checkMinimalPrice($product_id, $discount) public function getUserPerformanceByMonth(string $month) { + $session = session(); + $currentUser = $session->get('user'); + $isAdmin = in_array($currentUser['group_name'], ['SuperAdmin', 'Direction', 'DAF']); + $startOfMonth = date('Y-m-01', strtotime($month . '-01')); $endOfMonth = date('Y-m-t', strtotime($month . '-01')); @@ -794,24 +838,33 @@ public function getUserPerformanceByMonth(string $month) $results = []; foreach ($users as $user) { - $orderData = $this->db->table('orders') + $builder = $this->db->table('orders') ->select('COUNT(id) as total_user_order, SUM(net_amount) as total_prix_vente') ->where('user_id', $user->user_id) ->where('DATE(date_time) >=', $startOfMonth) ->where('DATE(date_time) <=', $endOfMonth) - ->whereIn('paid_status', [1, 3]) - ->get() - ->getRow(); + ->whereIn('paid_status', [1, 3]); + + // ✅ Filtre par magasin si pas admin + if (!$isAdmin && !empty($currentUser['store_id']) && $currentUser['store_id'] != 0) { + $builder->where('store_id', $currentUser['store_id']); + } + + $orderData = $builder->get()->getRow(); - $ids = $this->db->table('orders') + $idsBuilder = $this->db->table('orders') ->select('id') ->where('user_id', $user->user_id) ->where('DATE(date_time) >=', $startOfMonth) ->where('DATE(date_time) <=', $endOfMonth) - ->whereIn('paid_status', [1, 3]) - ->get() - ->getResult(); - + ->whereIn('paid_status', [1, 3]); + + // ✅ Filtre par magasin si pas admin + if (!$isAdmin && !empty($currentUser['store_id']) && $currentUser['store_id'] != 0) { + $idsBuilder->where('store_id', $currentUser['store_id']); + } + + $ids = $idsBuilder->get()->getResult(); $orderIds = array_map(fn($o) => $o->id, $ids); $results[] = [ @@ -866,4 +919,6 @@ public function getPerformanceByCaissier(int $caissierId, $startDate = null, $en ->getResultArray(); } + + } \ No newline at end of file diff --git a/app/Views/avances/avance.php b/app/Views/avances/avance.php index f5e412d5..f18a8368 100644 --- a/app/Views/avances/avance.php +++ b/app/Views/avances/avance.php @@ -1205,7 +1205,7 @@ function editFunc(id) { }); } -// ✅ AJOUTER cette nouvelle fonction juste après editFunc +// ✅ FONCTION AMÉLIORÉE pour remplir le modal d'édition function populateEditModal(r, id) { $('#avance_id_edit').val(r.avance_id || r.id || id); @@ -1228,24 +1228,19 @@ function populateEditModal(r, id) { // ✅ Gérer le produit selon le type if (r.type_avance === 'mere') { - // Pour avance MER : utiliser product_name (texte libre) var productNameMer = r.product_name || ''; $('#product_name_text_edit').val(productNameMer); } else if (r.type_avance === 'terre') { - // Pour avance TERRE : utiliser product_id (select) var productId = r.product_id || r.id_product; - // ✅ Si le produit existe dans le select, le sélectionner if (productId) { setTimeout(function() { $('#id_product_edit').val(productId); - // ✅ Vérifier si le produit existe dans le select if ($('#id_product_edit option:selected').val() == productId) { console.log('Produit trouvé et sélectionné:', productId); } else { console.warn('Produit non trouvé dans le select:', productId); - // ✅ Optionnel : Ajouter l'option si elle n'existe pas var productNameFromDB = r.product_name_db || 'Produit #' + productId; $('#id_product_edit').append( $('') @@ -1266,7 +1261,7 @@ function populateEditModal(r, id) { $(this).off('shown.bs.modal'); }); - // ✅ Gestionnaire de soumission (reste identique) + // ✅ GESTIONNAIRE DE SOUMISSION AMÉLIORÉ AVEC CONVERSION AUTOMATIQUE $('#update_avance_form').off('submit').on('submit', function(e) { e.preventDefault(); @@ -1276,6 +1271,7 @@ function populateEditModal(r, id) { var avance = unformatNumber($('#avance_amount_edit').val()); var brut = unformatNumber($('#gross_amount_edit').val()); + // ✅ VALIDATION pour avance sur terre if (typeAvance === 'terre') { var minAvance = brutEdit * 0.5; if (avance < minAvance) { @@ -1290,6 +1286,7 @@ function populateEditModal(r, id) { } } + // ✅ VALIDATION pour avance sur mer if (typeAvance === 'mere') { if (!$('#product_name_text_edit').val() || brut === 0 || avance === 0) { Swal.fire({ @@ -1318,15 +1315,38 @@ function populateEditModal(r, id) { success: function(res) { if (res.success === true) { $('#updateModal').modal('hide'); - Swal.fire({ - icon: 'success', - title: 'Succès', - text: res.messages, - timer: 2000, - showConfirmButton: false - }).then(() => { - location.reload(); - }); + + // ✅ NOUVEAU : Gestion de la conversion automatique + if (res.converted === true && res.redirect_url) { + Swal.fire({ + icon: 'success', + title: '🎉 Conversion automatique !', + html: '
' + + '

✅ Avance modifiée avec succès !

' + + '

🔄 L\'avance sur terre étant complète, elle a été automatiquement convertie en commande.

' + + '
' + + '

N° Commande : ' + (res.bill_no || 'N/A') + '

' + + '

Vous allez être redirigé vers la commande...

' + + '
', + timer: 4000, + timerProgressBar: true, + showConfirmButton: false, + allowOutsideClick: false + }).then(() => { + window.location.href = res.redirect_url; + }); + } else { + // ✅ Modification simple sans conversion + Swal.fire({ + icon: 'success', + title: 'Succès', + text: res.messages, + timer: 2000, + showConfirmButton: false + }).then(() => { + location.reload(); + }); + } } else { Swal.fire({ icon: 'error', @@ -1335,7 +1355,8 @@ function populateEditModal(r, id) { }); } }, - error: function() { + error: function(xhr, status, error) { + console.error('Erreur AJAX:', error); Swal.fire({ icon: 'error', title: 'Erreur de connexion', @@ -1475,42 +1496,5 @@ $(document).ready(function() { \ No newline at end of file diff --git a/app/Views/dashboard.php b/app/Views/dashboard.php index 8eb41fe4..d5ddd411 100644 --- a/app/Views/dashboard.php +++ b/app/Views/dashboard.php @@ -1,44 +1,8 @@
@@ -60,502 +24,980 @@
- - - -
-
- -
-
-

+ + -

Produit

-
-
- -
- Plus d'information -
-
- + +
+
+
+
+

Ar

+

Totale CAISSE

+
+
+ +
+
+
+ +
+
+
+

Ar

+

Totale MVOLA

+
+
+ +
+
+
+ +
+
+
+

Ar

+

Totale en espèce

+
+
+ +
+
+
+ +
+
+
+

Ar

+

Totale en banque

+
+
+ +
+
+
+
-
- -
-
-

+ +
+
+
+ +
+ Total Orders (Ventes complètes) + Ar +
+
+
+ +
+
+ +
+ Total Avances (Paiements partiels) + Ar +
+
+
+
-

Commande payée

-
-
- + +
+
+
+
+

Détail des Avances par Mode de Paiement

+
+
+
+
+
+
Ar
+ MVOLA
- Plus d'information
-
- -
- -
-
-

- -

Utilisateur

+
+
+
Ar
+ ESPÈCE
-
- -
- Plus d'information
-
- -
- -
-
-

- -

Point de vente

-
-
- -
- Plus d'information -
-
- - - -
- -
-
-

- -

Statistique des Commercials

-
-
- +
+
+
Ar
+ BANQUE
- Plus d'information
-
-
- -
- -
-
-

Ar

-

Totale FLUX

-
-
- -
-
-
- -
- -
-
-

Ar

-

Totale MVOLA

-
-
- +
+
+
+ + +
+

📊 Mes Performances de Vente

+ +
+ +
+
+
+
+
+
+
+
+
+
+

+ Liste de mes ventes validées +

+
+
+ +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + + + + + + + + + + + + + + + + + + + +
CaissierMoto vendueDate de ventePrix de vente
Total :
+
+
+
- -
- -
-
-

Ar

-

Totale en espece

-
-
- -
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+
+ +
+
+

+

Total Produits

-
- -
- -
-
-

Ar

-

Totale en banque

-
-
- -
+
+
+ + Plus d'information +
- -
-
-
-

Statistique des ventes par magasin

+ +
+ + + +
+
+
+
+

+ Informations Sécurité +

-
- +
+

+ Bienvenue sur votre tableau de bord sécurité. +

+

+ Vous avez accès à la consultation du nombre total de produits en stock. + Pour plus de détails, cliquez sur "Plus d'information" dans la carte ci-dessus. +

+
+
+
+ -
-
-
-

Liste des marques les plus vendues

-
-
- -
+ + + + +
+

Rapport de performance d'un mécanicien

+ +
+ +
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+ + + +
+
+ + + + + + + + + + +
MotosDésignationNuméro de sérieDébut de la réparationFin de la réparation
+
+
+
+
+
+
+
-
+
+
+ + + + + + + +
+
+ +
+
+

+

Produit

- -
-

Rapports des performances

- -
+
+ +
+ Plus d'information +
+
+ + +
+ +
+
+

+

Commande payée

+
+
+ +
+ Plus d'information +
+
+ + +
+ +
+
+

+

Utilisateur

+
+
+ +
+ Plus d'information +
+
+ + +
+ +
+
+

+

Point de vente

+
+
+ +
+ Plus d'information +
+
+ + +
+ +
+
+

+

Statistique des Commercials

+
+
+ +
+ Plus d'information +
+
+ +
-
-
-
-
-
-
- -
-
-
-
-

performances des commercials

-
-
-
-
- - -
-
- - -
-
- - -
-
-
- - -
-
- - - - - - - - - - - - - - - - - - - - - -
Nom et prénomEmailMotos vendueDate de ventePrix d'achatPrix de ventePoint de ventesBénefices
Total:
-
-
-
-
-
-
-
-
- -
-
-
-
-

📈 performances des Mécanicien

-
-
-
-
- - -
-
- - -
- get('user'); - if ($users["group_name"] === "Direction" || $users["group_name"] === "SuperAdmin" || $users["group_name"] === "DAF" ) : - - ?> -
- - -
- -
-
- - -
-
- - - - - - - - - - - -
MécaniciensMotosDésignationNuméro de sérieDébut de la réparationFin de la réparation
-
-
-
-
-
+
+ +
+
+
+

Ar

+

Totale FLUX

+
+
+ +
+
+
+ + +
+
+
+

Ar

+

Totale MVOLA

+
+
+ +
+
+
+ + +
+
+
+

Ar

+

Totale en espece

+
+
+ +
+
+
+ + +
+
+
+

Ar

+

Totale en banque

+
+
+ +
+
+
+
+ + +
+
+
+

Statistique des ventes par magasin

+
+
+ +
+
+ +
+
+
+

Liste des marques les plus vendues

+
+
+ +
+
+
+
+ + +
+

📊 Rapports des performances

+
+ +
+
+
+
+ + +
+
+
+
+
+
+

+ Performances des commercials +

+
+
+ +
+
+
+ + + +
+
+ + +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + +
Nom et prénomEmailMotos vendueDate de ventePrix d'achatPrix de ventePoint de ventesBénefices
Total :
+
+
-
- - +
+
+ +
+
+
+
+
+
+

+ Performances des Mécaniciens +

+
+
+ +
+
+ + +
+
+ + +
+ get('user'); + if ($users["group_name"] === "Direction" || $users["group_name"] === "SuperAdmin" || $users["group_name"] === "DAF"): + ?> +
+ + +
+ +
+
+ + +
+
+ + + + + + + + + + + + +
MécaniciensMotosDésignationNuméro de sérieDébut de la réparationFin de la réparation
+
+
+
+
+
+
- - + - // Export it - XLSX.writeFile(wb, 'export-commercial-performance.xlsx'); - }); - // Export en Excel mecanicien - $('#ExportBTN1').on('click', function () { - const table = document.getElementById('mecperformance'); - const wb = XLSX.utils.table_to_book(table, { sheet: "Feuille1" }); - XLSX.writeFile(wb, 'export-performance-mecanicien.xlsx'); - }); - + - -
-

Rapports des performances

-
diff --git a/app/Views/groups/delete.php b/app/Views/groups/delete.php index b61fb4dd..088fd408 100644 --- a/app/Views/groups/delete.php +++ b/app/Views/groups/delete.php @@ -1,7 +1,7 @@ -
+ -
+
-
+
@@ -47,10 +47,10 @@
- + \ No newline at end of file diff --git a/app/Views/groups/index.php b/app/Views/groups/index.php index 0026b189..65017d2b 100644 --- a/app/Views/groups/index.php +++ b/app/Views/groups/index.php @@ -1,125 +1,155 @@ + +
+ +
+

+ Gérer les + Rôles +

+ +
+ + +
+ +
+
- -
- -
-

- Gérer les - Rôles -

- -
- - - -
- -
-
- - getFlashdata('success')): ?> - - getFlashdata('error')): ?> - - + getFlashdata('success')): ?> + + getFlashdata('error')): ?> + + - - Ajouter un Rôle -

- + + Ajouter un Rôle +

+ -
-
-

Gérer les Rôles

-
- -
- - - - - - - - - - - - - $v): ?> - - +
+
+

Gérer les Rôles

+
+ +
+
DésignationAction
+ + + + + + + + + + + + $v): ?> + + - - + + - - - -
DésignationAction
- - - - - - - + + + + + -
-
- + + + + + + +
- +
- +
- - + +
+ +
+ +
+ -
- + + - + $("#mainUserNav").addClass('active'); + $("#manageGroupNav").addClass('active'); + }); + + // Fonction pour ouvrir le modal de confirmation + function confirmDelete(id, name) { + $('#roleName').text(name); + $('#deleteForm').attr('action', '' + id); + $('#deleteModal').modal('show'); + } + \ No newline at end of file diff --git a/app/Views/login.php b/app/Views/login.php index 60ef9f24..d5c4aa52 100644 --- a/app/Views/login.php +++ b/app/Views/login.php @@ -34,7 +34,24 @@ overflow: hidden; box-shadow: 0 6px 20px rgba(0,0,0,0.15); animation: fadeIn 0.8s ease; + position: relative; + backdrop-filter: blur(8px); } + .login-card::after { + content: ""; + position: absolute; + inset: 0; + z-index: -1; + background: linear-gradient(135deg, #ffffffaa, #e0e7ffaa, #dbeafeaa); + background-size: 300% 300%; + animation: gradientFlow 10s ease infinite; +} + +@keyframes gradientFlow { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } +} /* Partie gauche : image moto */ .login-image { @@ -243,10 +260,43 @@ font-size: 3em; } } + /* Fond de vagues animées */ +.animated-bg { + position: fixed; + inset: 0; + background: linear-gradient(to top, #cce7ff, #f8f9fa); /* bleu clair + blanc */ + overflow: hidden; + z-index: -1; +} + +/* Vague SVG */ +.wave { + position: absolute; + bottom: 0; + left: 0; + width: 200%; + height: 100%; + background: url('data:image/svg+xml;utf8,\ +\ +\ +') repeat-x; + animation: waveMove 12s linear infinite; +} + +@keyframes waveMove { + 0% { transform: translateX(0); } + 100% { transform: translateX(-50%); } +} + +
+
+
+ +
@@ -257,6 +307,7 @@
+
diff --git a/app/Views/orders/createbyid.php b/app/Views/orders/createbyid.php index 89f365b2..6e27adad 100644 --- a/app/Views/orders/createbyid.php +++ b/app/Views/orders/createbyid.php @@ -144,7 +144,6 @@


- @@ -167,7 +166,7 @@ - +
-
+

🛒 Détails des produits vendus

@@ -103,7 +103,7 @@
-
+

📦 Détails des produits en stock

@@ -123,7 +123,7 @@
+ class="card-header bg-white text-primary font-weight-bold">

📦 Exportation des produits vendus

diff --git a/app/Views/templates/header.php b/app/Views/templates/header.php index a3b40ea8..cb64e80e 100644 --- a/app/Views/templates/header.php +++ b/app/Views/templates/header.php @@ -113,801 +113,1589 @@
\ No newline at end of file diff --git a/app/Views/templates/header_menu.php b/app/Views/templates/header_menu.php index 86f6d09d..1d233fcf 100644 --- a/app/Views/templates/header_menu.php +++ b/app/Views/templates/header_menu.php @@ -12,8 +12,10 @@ Toggle navigation - -
+ + + @@ -39,15 +62,13 @@ /* Notifications non lues */ .notification_item.unread { font-weight: bold; - background-color: #f0f8ff; /* bleu clair */ + background-color: #f0f8ff; } - /* Icône bleue pour notifications non lues */ .icon-unread { - color: #007bff; /* bleu */ + color: #007bff; } - /* Style du bouton */ #markAllAsReadBtn { white-space: nowrap; } @@ -55,12 +76,33 @@ #markAllAsReadBtn:hover { background-color: #0056b3; } + + /* Style pour le dropdown utilisateur */ + .dropdown-item { + transition: background-color 0.2s; + } + + .dropdown-item:hover { + background-color: #f5f5f5; + text-decoration: none; + } + + .navbar-badge { + position: absolute; + top: -8px; + right: -8px; + padding: 3px 6px; + border-radius: 10px; + background: #f39c12; + color: white; + font-size: 10px; + } \ No newline at end of file diff --git a/app/Views/users/create.php b/app/Views/users/create.php index f7b53982..0fcb1934 100644 --- a/app/Views/users/create.php +++ b/app/Views/users/create.php @@ -1,143 +1,135 @@ + +
+ +
+

+ Gérer les + Utilisateurs +

+ +
+ + +
+
+
+ + getFlashdata('success')): ?> + + getFlashdata('error')): ?> + + +
+
+

Ajouter un utilisateur

+
- -
- -
-

- Gérer les - Utilisateurs -

- -
- - -
- -
-
- - getFlashdata('success')): ?> - - getFlashdata('error')): ?> - - +
+
-
-
-

Ajouter un utilisateur

-
- -
- - -
-
    - getErrors() as $error): ?> -
  • - -
-
+ +
+
    + getErrors() as $error): ?> +
  • + +
+
-
- - -
- -
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- -
- - -
-
+
+ + +
- + + +
- -
- - -
- -
- +
+
+
+