03122025
This commit is contained in:
parent
778e8332ee
commit
cb703c30f6
@ -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
|
||||
|
||||
@ -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');
|
||||
/**
|
||||
* 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();
|
||||
// Load the model and attempt login
|
||||
$userModel = new Users();
|
||||
$user = $userModel->attempt($email, $password);
|
||||
|
||||
$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
|
||||
]);
|
||||
|
||||
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.');
|
||||
// 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();
|
||||
|
||||
@ -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)
|
||||
*/
|
||||
|
||||
@ -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');
|
||||
|
||||
|
||||
@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
@ -84,7 +84,7 @@ class MecanicienController extends AdminController
|
||||
}
|
||||
|
||||
$image = '<img src="' . base_url('assets/images/product_image/' . $repa['image']) . '" alt="' . $repa['name'] . '" class="img-circle" width="50" height="50" />';
|
||||
$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');
|
||||
|
||||
$data['id'] = $users['id'];
|
||||
$reparation = $Mecanicien->getReparation($data['id']);
|
||||
$result = ['data' => []];
|
||||
|
||||
// ✅ RÉCUPÉRER LES PARAMÈTRES DE FILTRE
|
||||
$startDate = $this->request->getGet('startDate');
|
||||
$endDate = $this->request->getGet('endDate');
|
||||
$pvente = $this->request->getGet('pvente');
|
||||
|
||||
// Iterate through the data
|
||||
if($users['group_name'] == "SuperAdmin" || $users['group_name'] == "Direction"){
|
||||
// Log pour débogage
|
||||
log_message('debug', 'Filtres Mécanicien reçus - startDate: ' . $startDate . ', endDate: ' . $endDate . ', pvente: ' . $pvente);
|
||||
|
||||
$data['id'] = $users['id'];
|
||||
|
||||
// ✅ 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 = '<img src="' . base_url('assets/images/product_image/' . $repa['image']) . '" alt="' . $repa['name'] . '" class="img-circle" width="50" height="50" />';
|
||||
$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 = '<img src="' . base_url('assets/images/product_image/' . $repa['image']) . '" alt="' . $repa['name'] . '" class="img-circle" width="50" height="50" />';
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ class ProductCOntroller extends AdminController
|
||||
"Un nouveau Produit a été créé",
|
||||
"COMMERCIALE",
|
||||
$store_id1,
|
||||
'product/'
|
||||
'products/'
|
||||
);
|
||||
|
||||
return redirect()->to('/products');
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class Groups extends Model
|
||||
@ -11,10 +9,9 @@ class Groups extends Model
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'groups';
|
||||
protected $primaryKey = 'id'; // Primary key of your table
|
||||
protected $allowedFields = ['group_name', 'permission']; // Fields allowed for insert/update
|
||||
protected $useTimestamps = false; // Set to true if your table has `created_at` and `updated_at` columns
|
||||
|
||||
protected $primaryKey = 'id';
|
||||
protected $allowedFields = ['group_name', 'permission'];
|
||||
protected $useTimestamps = false;
|
||||
|
||||
/**
|
||||
* Get group data by groupId or all (excluding id = 1)
|
||||
@ -24,10 +21,9 @@ class Groups extends Model
|
||||
public function getGroupData($groupId = null)
|
||||
{
|
||||
if ($groupId) {
|
||||
return $this->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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -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(
|
||||
$('<option></option>')
|
||||
@ -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: '<div style="text-align: left; padding: 10px;">' +
|
||||
'<p style="margin: 10px 0;"><strong>✅ Avance modifiée avec succès !</strong></p>' +
|
||||
'<p style="margin: 10px 0;">🔄 L\'avance sur terre étant complète, elle a été <strong>automatiquement convertie en commande</strong>.</p>' +
|
||||
'<hr style="margin: 15px 0; border: none; border-top: 1px solid #ddd;">' +
|
||||
'<p style="margin: 10px 0;"><strong>N° Commande :</strong> ' + (res.bill_no || 'N/A') + '</p>' +
|
||||
'<p style="margin: 15px 0 5px 0; color: #666; font-style: italic;">Vous allez être redirigé vers la commande...</p>' +
|
||||
'</div>',
|
||||
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() {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* ✅ STYLES POUR LE BOUTON */
|
||||
#btnProcessExpired {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
#btnProcessExpired:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.swal2-container .table {
|
||||
margin: 0 auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.swal2-container .table th {
|
||||
background-color: #f8f9fa;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.swal2-container .table td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Style pour les inputs formatés */
|
||||
input.formatted-number {
|
||||
text-align: right;
|
||||
font-family: 'Courier New', monospace;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
/* Style pour les cellules de tableau formatées */
|
||||
.table td.number-cell {
|
||||
text-align: right;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- <div class="content-wrapper"> -->
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<!-- <section class="content-header">
|
||||
<h1>
|
||||
Gérer les
|
||||
<small>Roles</small>
|
||||
@ -10,11 +10,11 @@
|
||||
<li><a href="#"><i class="fa fa-dashboard"></i> Accueil</a></li>
|
||||
<li class="active">Roles</li>
|
||||
</ol>
|
||||
</section>
|
||||
</section> -->
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<!-- Small boxes (Stat box) -->
|
||||
<div class="row">
|
||||
<!-- <div class="row">
|
||||
<div class="col-md-12 col-xs-12">
|
||||
|
||||
<?php if (session()->getFlashdata('success')): ?>
|
||||
@ -36,7 +36,7 @@
|
||||
<a href="<?php echo base_url('groups') ?>" class="btn btn-warning">Retour</a>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- col-md-12 -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
@ -47,10 +47,10 @@
|
||||
</div>
|
||||
<!-- /.content-wrapper -->
|
||||
|
||||
|
||||
<!--
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$("#mainUserNav").addClass('active');
|
||||
$("#manageGroupNav").addClass('active');
|
||||
});
|
||||
</script>
|
||||
</script> -->
|
||||
@ -1,125 +1,155 @@
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
Gérer les
|
||||
<small>Rôles</small>
|
||||
</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#"><i class="fa fa-dashboard"></i> Accueil</a></li>
|
||||
<li class="active">Rôles</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<!-- Small boxes (Stat box) -->
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-xs-12">
|
||||
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
Gérer les
|
||||
<small>Rôles</small>
|
||||
</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#"><i class="fa fa-dashboard"></i> Accueil</a></li>
|
||||
<li class="active">Rôles</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<!-- Small boxes (Stat box) -->
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-xs-12">
|
||||
|
||||
<?php if(session()->getFlashdata('success')): ?>
|
||||
<div class="alert alert-success alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<?php echo session()->getFlashdata('success'); ?>
|
||||
</div>
|
||||
<?php elseif(session()->getFlashdata('error')): ?>
|
||||
<div class="alert alert-error alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<?php echo session()->getFlashdata('error'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if(in_array('createGroup', $user_permission)): ?>
|
||||
<a href="<?php echo base_url('groups/create') ?>" class="btn btn-primary">Ajouter un Rôle</a>
|
||||
<br /> <br />
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Gérer les Rôles</h3>
|
||||
</div>
|
||||
<!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<table id="groupTable" class="table table-bordered table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Désignation</th>
|
||||
<?php if(in_array('updateGroup', $user_permission) || in_array('deleteGroup', $user_permission)): ?>
|
||||
<th>Action</th>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<?php if($groups_data): ?>
|
||||
<?php foreach ($groups_data as $k => $v): ?>
|
||||
<tr>
|
||||
<td><?php echo $v['group_name']; ?></td>
|
||||
|
||||
<?php if(in_array('updateGroup', $user_permission) || in_array('deleteGroup', $user_permission)): ?>
|
||||
<td>
|
||||
<?php if(in_array('updateGroup', $user_permission)): ?>
|
||||
<a href="<?php echo base_url('groups/edit/'.$v['id']) ?>" class="btn btn-default"><i class="fa fa-edit"></i></a>
|
||||
<?php endif; ?>
|
||||
<?php if(in_array('deleteGroup', $user_permission)): ?>
|
||||
<a href="<?php echo base_url('groups/delete/'.$v['id']) ?>" class="btn btn-danger"><i class="fa fa-trash"></i></a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
<?php if(session()->getFlashdata('success')): ?>
|
||||
<div class="alert alert-success alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<?php echo session()->getFlashdata('success'); ?>
|
||||
</div>
|
||||
<!-- /.box -->
|
||||
<?php elseif(session()->getFlashdata('error')): ?>
|
||||
<div class="alert alert-error alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<?php echo session()->getFlashdata('error'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if(in_array('createGroup', $user_permission)): ?>
|
||||
<a href="<?php echo base_url('groups/create') ?>" class="btn btn-primary">Ajouter un Rôle</a>
|
||||
<br /> <br />
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Gérer les Rôles</h3>
|
||||
</div>
|
||||
<!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<table id="groupTable" class="table table-bordered table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Désignation</th>
|
||||
<?php if(in_array('updateGroup', $user_permission) || in_array('deleteGroup', $user_permission)): ?>
|
||||
<th>Action</th>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<?php if($groups_data): ?>
|
||||
<?php foreach ($groups_data as $k => $v): ?>
|
||||
<tr>
|
||||
<td><?php echo $v['group_name']; ?></td>
|
||||
|
||||
<?php if(in_array('updateGroup', $user_permission) || in_array('deleteGroup', $user_permission)): ?>
|
||||
<td>
|
||||
<?php if(in_array('updateGroup', $user_permission)): ?>
|
||||
<a href="<?php echo base_url('groups/edit/'.$v['id']) ?>" class="btn btn-default"><i class="fa fa-edit"></i></a>
|
||||
<?php endif; ?>
|
||||
<?php if(in_array('deleteGroup', $user_permission)): ?>
|
||||
<button type="button" class="btn btn-danger" onclick="confirmDelete(<?php echo $v['id']; ?>, '<?php echo addslashes($v['group_name']); ?>')">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
</div>
|
||||
<!-- col-md-12 -->
|
||||
<!-- /.box -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
<!-- col-md-12 -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
</div>
|
||||
<!-- /.content-wrapper -->
|
||||
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
<!-- Modal de confirmation de suppression -->
|
||||
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title" id="deleteModalLabel">Confirmation de suppression</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Voulez-vous vraiment supprimer le rôle <strong id="roleName"></strong> ?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<form id="deleteForm" method="post" style="display: inline;">
|
||||
<button type="button" class="btn btn-warning" data-dismiss="modal">Annuler</button>
|
||||
<button type="submit" class="btn btn-danger" name="confirm" value="Oui">
|
||||
<i class="fa fa-trash"></i> Oui, supprimer
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.content-wrapper -->
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
// datatable-fr.js
|
||||
$.extend(true, $.fn.dataTable.defaults, {
|
||||
language: {
|
||||
sProcessing: "Traitement en cours...",
|
||||
sSearch: "Rechercher :",
|
||||
sLengthMenu: "Afficher _MENU_ éléments",
|
||||
sInfo: "Affichage de l'élement _START_ à _END_ sur _TOTAL_ éléments",
|
||||
sInfoEmpty: "Affichage de l'élement 0 à 0 sur 0 élément",
|
||||
sInfoFiltered: "(filtré de _MAX_ éléments au total)",
|
||||
sLoadingRecords: "Chargement en cours...",
|
||||
sZeroRecords: "Aucun élément à afficher",
|
||||
sEmptyTable: "Aucune donnée disponible dans le tableau",
|
||||
oPaginate: {
|
||||
sFirst: "Premier",
|
||||
sPrevious: "Précédent",
|
||||
sNext: "Suivant",
|
||||
sLast: "Dernier"
|
||||
},
|
||||
oAria: {
|
||||
sSortAscending: ": activer pour trier la colonne par ordre croissant",
|
||||
sSortDescending: ": activer pour trier la colonne par ordre décroissant"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#groupTable').DataTable();
|
||||
|
||||
$("#mainUserNav").addClass('active');
|
||||
$("#manageGroupNav").addClass('active');
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
// datatable-fr.js
|
||||
$.extend(true, $.fn.dataTable.defaults, {
|
||||
language: {
|
||||
sProcessing: "Traitement en cours...",
|
||||
sSearch: "Rechercher :",
|
||||
sLengthMenu: "Afficher _MENU_ éléments",
|
||||
sInfo: "Affichage de l'élement _START_ à _END_ sur _TOTAL_ éléments",
|
||||
sInfoEmpty: "Affichage de l'élement 0 à 0 sur 0 élément",
|
||||
sInfoFiltered: "(filtré de _MAX_ éléments au total)",
|
||||
sLoadingRecords: "Chargement en cours...",
|
||||
sZeroRecords: "Aucun élément à afficher",
|
||||
sEmptyTable: "Aucune donnée disponible dans le tableau",
|
||||
oPaginate: {
|
||||
sFirst: "Premier",
|
||||
sPrevious: "Précédent",
|
||||
sNext: "Suivant",
|
||||
sLast: "Dernier"
|
||||
},
|
||||
oAria: {
|
||||
sSortAscending: ": activer pour trier la colonne par ordre croissant",
|
||||
sSortDescending: ": activer pour trier la colonne par ordre décroissant"
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
$('#groupTable').DataTable();
|
||||
|
||||
$("#mainUserNav").addClass('active');
|
||||
$("#manageGroupNav").addClass('active');
|
||||
});
|
||||
|
||||
// Fonction pour ouvrir le modal de confirmation
|
||||
function confirmDelete(id, name) {
|
||||
$('#roleName').text(name);
|
||||
$('#deleteForm').attr('action', '<?php echo base_url('groups/delete/'); ?>' + id);
|
||||
$('#deleteModal').modal('show');
|
||||
}
|
||||
</script>
|
||||
@ -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,\
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320">\
|
||||
<path fill="%23cce7ff" fill-opacity="0.5" d="M0,160L60,165.3C120,171,240,181,360,176C480,171,600,149,720,138.7C840,128,960,128,1080,138.7C1200,149,1320,171,1380,181.3L1440,192L1440,320L1380,320C1320,320,1200,320,1080,320C960,320,840,320,720,320C600,320,480,320,360,320C240,320,120,320,60,320L0,320Z"></path>\
|
||||
</svg>') repeat-x;
|
||||
animation: waveMove 12s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes waveMove {
|
||||
0% { transform: translateX(0); }
|
||||
100% { transform: translateX(-50%); }
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="animated-bg">
|
||||
<div class="wave"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Overlay de chargement -->
|
||||
<div class="loading-overlay" id="loadingOverlay">
|
||||
<div class="loading-content">
|
||||
@ -257,6 +307,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="login-card">
|
||||
|
||||
<!-- Image + message -->
|
||||
|
||||
@ -144,7 +144,6 @@
|
||||
</div>
|
||||
<br /> <br />
|
||||
|
||||
<!-- ✅ TABLEAU AVEC COLONNE PUISSANCE -->
|
||||
<table class="table table-bordered" id="product_info_table">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -167,7 +166,7 @@
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<!-- ✅ COLONNE PUISSANCE -->
|
||||
|
||||
<td>
|
||||
<input type="number" name="puissance[]" id="puissance_1"
|
||||
class="form-control" placeholder="CC"
|
||||
|
||||
@ -84,7 +84,7 @@
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-12 col-lg-12">
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-header bg-success text-white">
|
||||
<div class="card-header bg-white text-primary font-weight-bold">
|
||||
<h3 class="card-title m-0">🛒 Détails des produits vendus</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@ -103,7 +103,7 @@
|
||||
|
||||
<div class="col-md-12 col-lg-12">
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-header bg-warning text-dark">
|
||||
<div class="card-header bg-white text-primary font-weight-bold">
|
||||
<h3 class="card-title m-0">📦 Détails des produits en stock</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@ -123,7 +123,7 @@
|
||||
<div class="col-md-12 col-lg-12">
|
||||
<div class="card shadow-sm border-0 rounded-3">
|
||||
<div
|
||||
class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
|
||||
class="card-header bg-white text-primary font-weight-bold">
|
||||
<h3 class="card-title m-0">📦 Exportation des produits vendus</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -12,8 +12,10 @@
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
</a>
|
||||
|
||||
<!-- Notifications -->
|
||||
<ul class="navbar-nav" style="position: absolute; right: 15px; top: 50%; transform: translateY(-50%); margin: 0; padding: 0; list-style: none;">
|
||||
<!-- Navbar Right Menu -->
|
||||
<ul class="navbar-nav" style="position: absolute; right: 15px; top: 50%; transform: translateY(-50%); margin: 0; padding: 0; list-style: none; display: flex; align-items: center; gap: 20px;">
|
||||
|
||||
<!-- Notifications -->
|
||||
<li class="nav-item dropdown" style="position: relative;">
|
||||
<i class="fa fa-bell" id="notificationIcon" style="font-size: 20px; cursor: pointer; color:white;" data-toggle="dropdown"></i>
|
||||
<span id="notificationCount" class="badge badge-warning navbar-badge"></span>
|
||||
@ -30,6 +32,27 @@
|
||||
<div class="dropdown-divider"></div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- User Info (sans dropdown) -->
|
||||
<li class="nav-item" style="position: relative;">
|
||||
<div style="color: white; display: flex; align-items: center; gap: 10px; padding: 5px 10px; background: rgba(255,255,255,0.1); border-radius: 20px;">
|
||||
<i class="fa fa-user-circle" style="font-size: 24px;"></i>
|
||||
<div style="display: flex; flex-direction: column; line-height: 1.2;">
|
||||
<span style="font-size: 13px; font-weight: 600;">
|
||||
<?php
|
||||
$username = session()->get('username');
|
||||
echo $username ? esc($username) : 'Utilisateur';
|
||||
?>
|
||||
</span>
|
||||
<span style="font-size: 11px; opacity: 0.8;">
|
||||
<?php
|
||||
$role = session()->get('role');
|
||||
echo $role ? esc($role) : 'Aucun groupe';
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
@ -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;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function fetchNotifications() {
|
||||
$.ajax({
|
||||
url: '/notifications', // route NotificationController::getNotification
|
||||
url: '/notifications',
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
@ -68,15 +110,12 @@ function fetchNotifications() {
|
||||
let notificationHTML = '';
|
||||
|
||||
data.forEach(notif => {
|
||||
// Compter les notifications non lues
|
||||
if (notif.is_read == 0) {
|
||||
notificationCount++;
|
||||
}
|
||||
|
||||
const href = '/' + notif.link.replace(/^\/+/, '');
|
||||
const notifClass = notif.is_read == 0 ? "notification_item unread" : "notification_item";
|
||||
|
||||
// Icône uniquement pour non lu
|
||||
const iconHTML = notif.is_read == 0 ? '<i class="fa fa-exclamation-circle icon-unread mr-9"></i>' : '';
|
||||
|
||||
notificationHTML += `
|
||||
@ -93,11 +132,9 @@ function fetchNotifications() {
|
||||
`;
|
||||
});
|
||||
|
||||
// Injecter les notifications
|
||||
$('#notificationList').html(notificationHTML);
|
||||
$('#notificationHeader').text(data.length + ' Notifications');
|
||||
|
||||
// Badge pour non lues
|
||||
if (notificationCount > 0) {
|
||||
$('#notificationCount').text(notificationCount).show();
|
||||
$('#markAllAsReadBtn').show();
|
||||
@ -106,7 +143,6 @@ function fetchNotifications() {
|
||||
$('#markAllAsReadBtn').hide();
|
||||
}
|
||||
|
||||
// Ajouter l'événement clic pour marquer comme lu
|
||||
const items = document.querySelectorAll('.notification_item');
|
||||
items.forEach(item => {
|
||||
item.addEventListener('click', () => {
|
||||
@ -118,7 +154,6 @@ function fetchNotifications() {
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log("Notification marked as read:", data);
|
||||
// l'icône disparaîtra au prochain fetch
|
||||
})
|
||||
.catch(error => console.error("Error:", error));
|
||||
});
|
||||
@ -131,7 +166,6 @@ function fetchNotifications() {
|
||||
});
|
||||
}
|
||||
|
||||
// Fonction pour marquer toutes les notifications comme lues
|
||||
function markAllAsRead() {
|
||||
fetch("<?= base_url('notifications/markAllAsRead') ?>", {
|
||||
method: "POST",
|
||||
@ -140,21 +174,17 @@ function markAllAsRead() {
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log("All notifications marked as read:", data);
|
||||
// Rafraîchir les notifications immédiatement
|
||||
fetchNotifications();
|
||||
})
|
||||
.catch(error => console.error("Error:", error));
|
||||
}
|
||||
|
||||
// Attacher l'événement au bouton
|
||||
$(document).on('click', '#markAllAsReadBtn', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
markAllAsRead();
|
||||
});
|
||||
|
||||
// Rafraîchir toutes les 10 secondes
|
||||
setInterval(fetchNotifications, 10000);
|
||||
// Premier chargement
|
||||
fetchNotifications();
|
||||
</script>
|
||||
@ -1,143 +1,135 @@
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
Gérer les
|
||||
<small>Utilisateurs</small>
|
||||
</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#"><i class="fa fa-dashboard"></i> Accueil</a></li>
|
||||
<li class="active">Utilisateurs</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-xs-12">
|
||||
|
||||
<?php if(session()->getFlashdata('success')): ?>
|
||||
<div class="alert alert-success alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<?php echo session()->getFlashdata('success'); ?>
|
||||
</div>
|
||||
<?php elseif(session()->getFlashdata('error')): ?>
|
||||
<div class="alert alert-error alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<?php echo session()->getFlashdata('error'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
Gérer les
|
||||
<small>Utilisateurs</small>
|
||||
</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#"><i class="fa fa-dashboard"></i> Accueil</a></li>
|
||||
<li class="active">Utilisateurs</li>
|
||||
</ol>
|
||||
</section>
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Ajouter un utilisateur</h3>
|
||||
</div>
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<!-- Small boxes (Stat box) -->
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-xs-12">
|
||||
|
||||
<?php if(session()->getFlashdata('success')): ?>
|
||||
<div class="alert alert-success alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<?php echo session()->getFlashdata('success'); ?>
|
||||
</div>
|
||||
<?php elseif(session()->getFlashdata('error')): ?>
|
||||
<div class="alert alert-error alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<?php echo session()->getFlashdata('error'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<form role="form" action="<?php base_url('users/create') ?>" method="post">
|
||||
<div class="box-body">
|
||||
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Ajouter un utilisateur</h3>
|
||||
</div>
|
||||
<form role="form" action="<?php base_url('users/create') ?>" method="post">
|
||||
<div class="box-body">
|
||||
|
||||
<?php if (isset($validation)): ?>
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
<?php foreach ($validation->getErrors() as $error): ?>
|
||||
<li><?= esc($error) ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php if (isset($validation)): ?>
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
<?php foreach ($validation->getErrors() as $error): ?>
|
||||
<li><?= esc($error) ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="groups">Rôle</label>
|
||||
<select class="form-control" id="groups" name="groups">
|
||||
<option value="">Sélectionnez un rôle</option>
|
||||
<?php foreach ($group_data as $k => $v): ?>
|
||||
<option value="<?php echo $v['id'] ?>"><?php echo $v['group_name'] ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="username">Nom d'utilisateur</label>
|
||||
<input type="text" class="form-control" id="username" name="username" placeholder="Username" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" class="form-control" id="email" name="email" placeholder="Email" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Mot de passe</label>
|
||||
<input type="password" class="form-control" id="password" name="password" placeholder="Password" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="cpassword">Confirmation mot de passe</label>
|
||||
<input type="password" class="form-control" id="cpassword" name="cpassword" placeholder="Confirm Password" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="fname">Nom</label>
|
||||
<input type="text" class="form-control" id="fname" name="fname" placeholder="First name" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="lname">Prénom</label>
|
||||
<input type="text" class="form-control" id="lname" name="lname" placeholder="Last name" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="phone">Téléphone</label>
|
||||
<input type="text" class="form-control" id="phone" name="phone" placeholder="Phone" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="gender">Genre</label>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="gender" id="male" value="1">
|
||||
Homme
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="gender" id="female" value="2">
|
||||
Femme
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="store-container" style="display: none;">
|
||||
<label for="store">Magasin</label>
|
||||
<select class="form-control select_group" id="store" name="store">
|
||||
<option value="0">Sélectionnez un magasin</option>
|
||||
<?php foreach ($stores as $k => $v): ?>
|
||||
<option value="<?php echo $v['id'] ?>"><?php echo $v['name'] ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="groups">Rôle</label>
|
||||
<select class="form-control" id="groups" name="groups">
|
||||
<option value="">Sélectionnez un rôle</option>
|
||||
<?php foreach ($group_data as $k => $v): ?>
|
||||
<option value="<?php echo $v['id'] ?>"><?php echo $v['group_name'] ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
|
||||
<div class="box-footer">
|
||||
<button type="submit" class="btn btn-primary">Enregistrer</button>
|
||||
<a href="<?php echo base_url('users/') ?>" class="btn btn-warning">Retour</a>
|
||||
<div class="form-group">
|
||||
<label for="username">Nom d'utilisateur</label>
|
||||
<input type="text" class="form-control" id="username" name="username" placeholder="Username" autocomplete="off">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- /.box -->
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" class="form-control" id="email" name="email" placeholder="Email" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Mot de passe</label>
|
||||
<input type="password" class="form-control" id="password" name="password" placeholder="Password" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="cpassword">Confirmation mot de passe</label>
|
||||
<input type="password" class="form-control" id="cpassword" name="cpassword" placeholder="Confirm Password" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="fname">Nom</label>
|
||||
<input type="text" class="form-control" id="fname" name="fname" placeholder="First name" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="lname">Prénom</label>
|
||||
<input type="text" class="form-control" id="lname" name="lname" placeholder="Last name" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="phone">Téléphone</label>
|
||||
<input type="text" class="form-control" id="phone" name="phone" placeholder="Phone" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="gender">Genre</label>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="gender" id="male" value="1">
|
||||
Homme
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="gender" id="female" value="2">
|
||||
Femme
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Champ magasin toujours affiché -->
|
||||
<div class="form-group" id="store-container">
|
||||
<label for="store">Magasin</label>
|
||||
<select class="form-control select_group" id="store" name="store">
|
||||
<option value="0">Sélectionnez un magasin</option>
|
||||
<?php foreach ($stores as $k => $v): ?>
|
||||
<option value="<?php echo $v['id'] ?>"><?php echo $v['name'] ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="box-footer">
|
||||
<button type="submit" class="btn btn-primary">Enregistrer</button>
|
||||
<a href="<?php echo base_url('users/') ?>" class="btn btn-warning">Retour</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- col-md-12 -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
</div>
|
||||
<!-- /.content-wrapper -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
@ -146,21 +138,6 @@
|
||||
$("#mainUserNav").addClass('active');
|
||||
$("#createUserNav").addClass('active');
|
||||
|
||||
$('#groups').on('change', function () {
|
||||
// Get the selected option's text
|
||||
let selectedText = $('#groups option:selected').text();
|
||||
|
||||
// Check if the selected text matches "commercial" (case insensitive)
|
||||
if (selectedText.toLowerCase().includes('commercial')) {
|
||||
// Show the store dropdown
|
||||
$('#store-container').show();
|
||||
} else {
|
||||
// Hide the store dropdown
|
||||
$('#store-container').hide();
|
||||
}
|
||||
});
|
||||
|
||||
// SUPPRIMÉ : plus aucune condition sur le rôle
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user