Sarobidy22 1 month ago
parent
commit
10f3dae939
  1. 58
      app/Controllers/AvanceController.php
  2. 4
      app/Controllers/Dashboard.php
  3. 2
      app/Controllers/MecanicienController.php
  4. 192
      app/Controllers/OrderController.php
  5. 171
      app/Controllers/RecouvrementController.php
  6. 129
      app/Controllers/RemiseController.php
  7. 2
      app/Controllers/ReportController.php
  8. 199
      app/Controllers/SortieCaisseController.php
  9. 2
      app/Controllers/StatistiqueController.php
  10. 95
      app/Models/Avance.php
  11. 2
      app/Models/Mecanicien.php
  12. 8
      app/Models/Orders.php
  13. 4
      app/Models/Products.php
  14. 4
      app/Models/Recouvrement.php
  15. 26
      app/Models/Remise.php
  16. 2
      app/Models/Securite.php
  17. 123
      app/Models/SortieCaisse.php
  18. 8
      app/Views/avances/avance.php
  19. 2
      app/Views/dashboard.php
  20. 135
      app/Views/login.php
  21. 4
      app/Views/orders/avance.php
  22. 2
      app/Views/orders/edit.php
  23. 84
      app/Views/orders/index.php
  24. 144
      app/Views/reports/index.php
  25. 16
      app/Views/sortieCaisse/index.php
  26. 163
      app/Views/statistic/index.php
  27. 1
      app/Views/templates/header.php

58
app/Controllers/AvanceController.php

@ -31,7 +31,7 @@ class AvanceController extends AdminController
private function isAdmin($user) private function isAdmin($user)
{ {
return in_array($user['group_name'], ['Conseil', 'Direction']); return in_array($user['group_name'], ['SuperAdmin','DAF','Direction']);
} }
private function isCommerciale($user) private function isCommerciale($user)
@ -50,7 +50,7 @@ private function buildActionButtons($value, $isAdmin, $isOwner, $isCaissier = fa
{ {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isDirection = in_array($users['group_name'], ['Direction', 'Conseil']); $isDirection = in_array($users['group_name'], ['Direction', 'SuperAdmin','DAF']);
$buttons = ''; $buttons = '';
@ -468,15 +468,49 @@ public function fetchExpiredAvance()
$Products->update($data['product_id'], ['product_sold' => 1]); $Products->update($data['product_id'], ['product_sold' => 1]);
} }
// ✅ NOUVELLE FONCTIONNALITÉ : Envoyer notification au Conseil // ✅ MODIFICATION PRINCIPALE : Envoyer notifications à TOUS les stores
$db = \Config\Database::connect();
// Récupérer tous les stores
$storesQuery = $db->table('stores')->select('id')->get();
$allStores = $storesQuery->getResultArray();
$customerName = $this->request->getPost('customer_name_avance');
$avanceAmount = number_format((float)$this->request->getPost('avance_amount'), 0, ',', ' ');
$typeAvanceLabel = $type_avance === 'terre' ? 'SUR TERRE' : 'SUR MER';
$notificationMessage = "Nouvelle avance {$typeAvanceLabel} créée par {$users['firstname']} {$users['lastname']} - Client: {$customerName} - Montant: {$avanceAmount} Ar";
// ✅ Envoyer notification à DAF, Direction et SuperAdmin de TOUS les stores
foreach ($allStores as $store) {
$storeId = (int)$store['id'];
// Notification pour DAF
$Notification->createNotification( $Notification->createNotification(
'Une nouvelle avance a été créée', $notificationMessage,
"DAF", "DAF",
(int)$users['store_id'], $storeId,
'avances' 'avances'
); );
// ✅ NOUVELLE FONCTIONNALITÉ : Envoyer notification à la Caissière si l'utilisateur est COMMERCIALE // Notification pour Direction
$Notification->createNotification(
$notificationMessage,
"Direction",
$storeId,
'avances'
);
// Notification pour SuperAdmin
$Notification->createNotification(
$notificationMessage,
"SuperAdmin",
$storeId,
'avances'
);
}
// ✅ Notification à la Caissière UNIQUEMENT du store concerné (si l'utilisateur est COMMERCIALE)
if ($this->isCommerciale($users)) { if ($this->isCommerciale($users)) {
$Notification->createNotification( $Notification->createNotification(
'Une nouvelle avance a été créée par un commercial', 'Une nouvelle avance a été créée par un commercial',
@ -486,6 +520,8 @@ public function fetchExpiredAvance()
); );
} }
log_message('info', "✅ Avance {$avance_id} créée - Notifications envoyées à DAF/Direction/SuperAdmin de tous les stores");
return $this->response->setJSON([ return $this->response->setJSON([
'success' => true, 'success' => true,
'messages' => 'Avance créée avec succès !', 'messages' => 'Avance créée avec succès !',
@ -506,7 +542,6 @@ public function fetchExpiredAvance()
} }
} }
public function updateAvance() public function updateAvance()
{ {
$this->verifyRole('updateAvance'); $this->verifyRole('updateAvance');
@ -1139,7 +1174,7 @@ public function getInvoicePreview($avance_id)
$users = $session->get('user'); $users = $session->get('user');
$isCaissier = $this->isCaissier($users); $isCaissier = $this->isCaissier($users);
$isDirection = in_array($users['group_name'], ['Direction', 'Conseil']); $isDirection = in_array($users['group_name'], ['Direction', 'SuperAdmin','DAF']);
if (!$isCaissier && !$isDirection) { if (!$isCaissier && !$isDirection) {
return $this->response->setJSON([ return $this->response->setJSON([
@ -1501,6 +1536,13 @@ public function notifyPrintInvoice()
'avances' 'avances'
); );
$Notification->createNotification(
"Il y a une avance N°{$avanceNumber} pour le client {$customerName}",
"SuperAdmin",
(int)$users['store_id'],
'avances'
);
return $this->response->setJSON([ return $this->response->setJSON([
'success' => true, 'success' => true,
'messages' => 'Facture imprimée avec succès ! Notification envoyée à la Direction.' 'messages' => 'Facture imprimée avec succès ! Notification envoyée à la Direction.'

4
app/Controllers/Dashboard.php

@ -136,7 +136,7 @@ class Dashboard extends AdminController
$data['total_products'] = $productModel->countProductsByUserStore(); $data['total_products'] = $productModel->countProductsByUserStore();
// === ✅ Récupérer le nom du store pour l'affichage === // === ✅ Récupérer le nom du store pour l'affichage ===
$isAdmin = in_array($user_id['group_name'], ['DAF', 'Direction']); $isAdmin = in_array($user_id['group_name'], ['DAF', 'Direction','SuperAdmin']);
if (!$isAdmin && !empty($user_id['store_id']) && $user_id['store_id'] != 0) { if (!$isAdmin && !empty($user_id['store_id']) && $user_id['store_id'] != 0) {
$store = $storeModel->getStoresData($user_id['store_id']); $store = $storeModel->getStoresData($user_id['store_id']);
@ -219,7 +219,7 @@ class Dashboard extends AdminController
$data['isMecanicien'] = false; $data['isMecanicien'] = false;
$data['isSecurite'] = false; $data['isSecurite'] = false;
if ($user_id['group_name'] == "Direction" || $user_id['group_name'] == "DAF") { if ($user_id['group_name'] == "Direction" || $user_id['group_name'] == "DAF" || $user_id['group_name'] == "SuperAdmin") {
$data['is_admin'] = true; $data['is_admin'] = true;
} }

2
app/Controllers/MecanicienController.php

@ -319,7 +319,7 @@ class MecanicienController extends AdminController
// Iterate through the data // Iterate through the data
if($users['group_name'] == "Conseil" || $users['group_name'] == "Direction"){ if($users['group_name'] == "SuperAdmin" || $users['group_name'] == "Direction"){
foreach ($reparation as $key => $repa) { 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" />'; $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']); $produit = esc($repa['name']);

192
app/Controllers/OrderController.php

@ -107,11 +107,11 @@ class OrderController extends AdminController
// Statut de paiement // Statut de paiement
if ($value['paid_status'] == 1) { if ($value['paid_status'] == 1) {
$paid_status = '<span class="label label-success">Validé</span>'; $paid_status = '<span class="label label-success">payé</span>';
} elseif ($value['paid_status'] == 2) { } elseif ($value['paid_status'] == 2) {
$paid_status = '<span class="label label-warning">En Attente</span>'; $paid_status = '<span class="label label-warning">En Attente</span>';
} elseif ($value['paid_status'] == 3) { } elseif ($value['paid_status'] == 3) {
$paid_status = '<span class="label label-info">Validé et Livré</span>'; $paid_status = '<span class="label label-info">payé et Livré</span>';
} else { } else {
$paid_status = '<span class="label label-danger">Refusé</span>'; $paid_status = '<span class="label label-danger">Refusé</span>';
} }
@ -149,7 +149,7 @@ class OrderController extends AdminController
// ======================================== // ========================================
// POUR DIRECTION OU DAF // POUR DIRECTION OU DAF
// ======================================== // ========================================
elseif($users['group_name'] == "Direction" || $users['group_name'] == "DAF"){ elseif($users['group_name'] == "Direction" || $users['group_name'] == "DAF" || $users['group_name'] == "SuperAdmin" ){
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
$date_time = date('d-m-Y h:i a', strtotime($value['date_time'])); $date_time = date('d-m-Y h:i a', strtotime($value['date_time']));
@ -172,11 +172,11 @@ class OrderController extends AdminController
// Statut de paiement // Statut de paiement
if ($value['paid_status'] == 1) { if ($value['paid_status'] == 1) {
$paid_status = '<span class="label label-success">Validé</span>'; $paid_status = '<span class="label label-success">payé</span>';
} elseif ($value['paid_status'] == 2) { } elseif ($value['paid_status'] == 2) {
$paid_status = '<span class="label label-warning">En Attente</span>'; $paid_status = '<span class="label label-warning">En Attente</span>';
} elseif ($value['paid_status'] == 3) { } elseif ($value['paid_status'] == 3) {
$paid_status = '<span class="label label-info">Validé et Livré</span>'; $paid_status = '<span class="label label-info">Payé et Livré</span>';
} else { } else {
$paid_status = '<span class="label label-danger">Refusé</span>'; $paid_status = '<span class="label label-danger">Refusé</span>';
} }
@ -255,11 +255,11 @@ class OrderController extends AdminController
// Statut de paiement // Statut de paiement
if ($value['paid_status'] == 1) { if ($value['paid_status'] == 1) {
$paid_status = '<span class="label label-success">Validé</span>'; $paid_status = '<span class="label label-success">Payé</span>';
} elseif ($value['paid_status'] == 2) { } elseif ($value['paid_status'] == 2) {
$paid_status = '<span class="label label-warning">En Attente</span>'; $paid_status = '<span class="label label-warning">En Attente</span>';
} elseif ($value['paid_status'] == 3) { } elseif ($value['paid_status'] == 3) {
$paid_status = '<span class="label label-info">Validé et Livré</span>'; $paid_status = '<span class="label label-info">Payé et Livré</span>';
} else { } else {
$paid_status = '<span class="label label-danger">Refusé</span>'; $paid_status = '<span class="label label-danger">Refusé</span>';
} }
@ -331,8 +331,12 @@ class OrderController extends AdminController
public function create() /**
{ * ✅ AMÉLIORATION : Notifications centralisées pour Direction/DAF/SuperAdmin (tous stores)
*/
public function create()
{
$this->verifyRole('createOrder'); $this->verifyRole('createOrder');
$data['page_title'] = $this->pageTitle; $data['page_title'] = $this->pageTitle;
@ -343,14 +347,12 @@ class OrderController extends AdminController
return redirect()->back()->withInput()->with('errors', ['product' => 'Chaque produit sélectionné doit être unique.']); return redirect()->back()->withInput()->with('errors', ['product' => 'Chaque produit sélectionné doit être unique.']);
} }
// ✅ AJOUT DES RÈGLES DE VALIDATION
$validation->setRules([ $validation->setRules([
'product[]' => 'required', 'product[]' => 'required',
'customer_type' => 'required', 'customer_type' => 'required',
'source' => 'required' 'source' => 'required'
]); ]);
// ✅ AJOUT DES DONNÉES DE VALIDATION
$validationData = [ $validationData = [
'product[]' => $this->request->getPost('product[]'), 'product[]' => $this->request->getPost('product[]'),
'customer_type' => $this->request->getPost('customer_type'), 'customer_type' => $this->request->getPost('customer_type'),
@ -369,7 +371,6 @@ class OrderController extends AdminController
$bill_no = $this->generateBillNo($users['store_id']); $bill_no = $this->generateBillNo($users['store_id']);
// Récupération des produits
$posts = $this->request->getPost('product[]'); $posts = $this->request->getPost('product[]');
$rates = $this->request->getPost('rate_value[]'); $rates = $this->request->getPost('rate_value[]');
$amounts = $this->request->getPost('amount_value[]'); $amounts = $this->request->getPost('amount_value[]');
@ -404,7 +405,6 @@ class OrderController extends AdminController
} }
} }
// Calculer le montant à payer et net_amount
$montant_a_payer = ($discount > 0) ? $discount : $gross_amount; $montant_a_payer = ($discount > 0) ? $discount : $gross_amount;
$tranche_1 = (float)$this->request->getPost('tranche_1') ?? 0; $tranche_1 = (float)$this->request->getPost('tranche_1') ?? 0;
@ -416,15 +416,14 @@ class OrderController extends AdminController
$net_amount = $montant_a_payer; $net_amount = $montant_a_payer;
} }
// ✅ AJOUT DES NOUVEAUX CHAMPS ICI
$data = [ $data = [
'bill_no' => $bill_no, 'bill_no' => $bill_no,
'customer_name' => $this->request->getPost('customer_name'), 'customer_name' => $this->request->getPost('customer_name'),
'customer_address' => $this->request->getPost('customer_address'), 'customer_address' => $this->request->getPost('customer_address'),
'customer_phone' => $this->request->getPost('customer_phone'), 'customer_phone' => $this->request->getPost('customer_phone'),
'customer_cin' => $this->request->getPost('customer_cin'), 'customer_cin' => $this->request->getPost('customer_cin'),
'customer_type' => $this->request->getPost('customer_type'), // ✅ NOUVEAU 'customer_type' => $this->request->getPost('customer_type'),
'source' => $this->request->getPost('source'), // ✅ NOUVEAU 'source' => $this->request->getPost('source'),
'date_time' => date('Y-m-d H:i:s'), 'date_time' => date('Y-m-d H:i:s'),
'service_charge_rate' => 0, 'service_charge_rate' => 0,
'vat_charge_rate' => 0, 'vat_charge_rate' => 0,
@ -450,9 +449,10 @@ class OrderController extends AdminController
session()->setFlashdata('success', 'Créé avec succès'); session()->setFlashdata('success', 'Créé avec succès');
$Notification = new NotificationController(); $Notification = new NotificationController();
$Stores = new Stores();
if ($discount > 0) { if ($discount > 0) {
// Logique demande de remise... // ✅ DEMANDE DE REMISE : NOTIFIER TOUS LES STORES
$Order_item1 = new OrderItems(); $Order_item1 = new OrderItems();
$order_item_data = $Order_item1->getOrdersItemData($order_id); $order_item_data = $Order_item1->getOrdersItemData($order_id);
$product_ids = array_column($order_item_data, 'product_id'); $product_ids = array_column($order_item_data, 'product_id');
@ -489,20 +489,91 @@ class OrderController extends AdminController
$Remise = new Remise(); $Remise = new Remise();
$id_remise = $Remise->addDemande($data1); $id_remise = $Remise->addDemande($data1);
// ✅ RÉCUPÉRER TOUS LES STORES
$allStores = $Stores->getActiveStore();
$montantFormatted = number_format($discount, 0, ',', ' ');
$message = "💰 Nouvelle demande de remise : {$montantFormatted} Ar<br>" .
"Commande : {$bill_no}<br>" .
"Store : " . $this->returnStore($users['store_id']) . "<br>" .
"Demandeur : {$users['firstname']} {$users['lastname']}";
// ✅ NOTIFIER SUPERADMIN, DIRECTION, DAF DE TOUS LES STORES
if (is_array($allStores) && count($allStores) > 0) {
foreach ($allStores as $store) {
// SuperAdmin (validation)
$Notification->createNotification( $Notification->createNotification(
"Nouvelle demande de remise à valider - Commande " . $bill_no, $message,
"SuperAdmin",
(int)$store['id'],
'remise/'
);
// Direction (consultation)
$Notification->createNotification(
$message . "<br><em>Pour information</em>",
"Direction", "Direction",
(int)$users['store_id'], (int)$store['id'],
"remise/" 'remise/'
);
// DAF (consultation)
$Notification->createNotification(
$message . "<br><em>Pour information</em>",
"DAF",
(int)$store['id'],
'remise/'
); );
}
}
} else { } else {
// ✅ COMMANDE SANS REMISE : NOTIFIER CAISSIÈRE DU STORE + TOUS LES CENTRAUX
// Caissière du store concerné
$Notification->createNotification( $Notification->createNotification(
"Nouvelle commande à valider - " . $bill_no, "📦 Nouvelle commande à valider : {$bill_no}<br>" .
"Client : {$data['customer_name']}<br>" .
"Montant : " . number_format($gross_amount, 0, ',', ' ') . " Ar",
"Caissière", "Caissière",
(int)$users['store_id'], (int)$users['store_id'],
"orders" "orders"
); );
// ✅ RÉCUPÉRER TOUS LES STORES
$allStores = $Stores->getActiveStore();
$messageGlobal = "📋 Nouvelle commande créée : {$bill_no}<br>" .
"Store : " . $this->returnStore($users['store_id']) . "<br>" .
"Client : {$data['customer_name']}<br>" .
"Montant : " . number_format($gross_amount, 0, ',', ' ') . " Ar<br>" .
"Créée par : {$users['firstname']} {$users['lastname']}";
// ✅ NOTIFIER DIRECTION, DAF, SUPERADMIN DE TOUS LES STORES
if (is_array($allStores) && count($allStores) > 0) {
foreach ($allStores as $store) {
$Notification->createNotification(
$messageGlobal,
"Direction",
(int)$store['id'],
'orders'
);
$Notification->createNotification(
$messageGlobal,
"DAF",
(int)$store['id'],
'orders'
);
$Notification->createNotification(
$messageGlobal,
"SuperAdmin",
(int)$store['id'],
'orders'
);
}
}
} }
if ($users["group_name"] != "COMMERCIALE") { if ($users["group_name"] != "COMMERCIALE") {
@ -534,8 +605,7 @@ class OrderController extends AdminController
return $this->render_template('orders/create', $data); return $this->render_template('orders/create', $data);
} }
} }
/** /**
* Marquer une commande comme livrée * Marquer une commande comme livrée
* Accessible uniquement par le rôle SECURITE * Accessible uniquement par le rôle SECURITE
@ -583,15 +653,42 @@ public function markAsDelivered()
$updated = $Orders->update((int)$order_id, ['paid_status' => 3]); $updated = $Orders->update((int)$order_id, ['paid_status' => 3]);
if ($updated) { if ($updated) {
// Créer une notification // Créer une notification centralisée pour tous les stores
try { try {
$Notification = new NotificationController(); $Notification = new NotificationController();
$Stores = new Stores();
$allStores = $Stores->getActiveStore();
$messageGlobal = "📦 Commande livrée : {$current_order['bill_no']}<br>" .
"Store : " . $this->returnStore($current_order['store_id']) . "<br>" .
"Client : {$current_order['customer_name']}<br>" .
"Livrée par : {$users['firstname']} {$users['lastname']}";
// ✅ NOTIFIER DIRECTION, DAF, SUPERADMIN DE TOUS LES STORES
if (is_array($allStores) && count($allStores) > 0) {
foreach ($allStores as $store) {
$Notification->createNotification( $Notification->createNotification(
"Commande " . $current_order['bill_no'] . " livrée avec succès", $messageGlobal,
"Direction", "Direction",
(int)$current_order['store_id'], (int)$store['id'],
"orders" 'orders'
);
$Notification->createNotification(
$messageGlobal,
"DAF",
(int)$store['id'],
'orders'
);
$Notification->createNotification(
$messageGlobal,
"SuperAdmin",
(int)$store['id'],
'orders'
); );
}
}
} catch (\Exception $e) { } catch (\Exception $e) {
// Si la notification échoue, on continue quand même // Si la notification échoue, on continue quand même
log_message('error', 'Erreur notification: ' . $e->getMessage()); log_message('error', 'Erreur notification: ' . $e->getMessage());
@ -611,7 +708,6 @@ public function markAsDelivered()
return $this->response->setJSON($response); return $this->response->setJSON($response);
} }
public function getProductValueById() public function getProductValueById()
{ {
$product_id = $this->request->getPost('product_id'); $product_id = $this->request->getPost('product_id');
@ -793,10 +889,12 @@ public function update(int $id)
$Notification = new NotificationController(); $Notification = new NotificationController();
// ✅ NOTIFICATION CENTRALISÉE POUR VALIDATION
if ($old_paid_status == 2 && $paid_status == 1) { if ($old_paid_status == 2 && $paid_status == 1) {
$customer_name = $this->request->getPost('customer_name'); $customer_name = $this->request->getPost('customer_name');
$bill_no = $current_order['bill_no']; $bill_no = $current_order['bill_no'];
// ✅ Notification SECURITE du store concerné
$Notification->createNotification( $Notification->createNotification(
"Commande validée: {$bill_no} - Client: {$customer_name}", "Commande validée: {$bill_no} - Client: {$customer_name}",
"SECURITE", "SECURITE",
@ -804,13 +902,39 @@ public function update(int $id)
'orders' 'orders'
); );
if ($role === 'Caissière') { // ✅ RÉCUPÉRER TOUS LES STORES
$Stores = new Stores();
$allStores = $Stores->getActiveStore();
$messageGlobal = "✅ Commande validée : {$bill_no}<br>" .
"Store : " . $this->returnStore($user['store_id']) . "<br>" .
"Client : {$customer_name}<br>" .
"Validée par : {$user['firstname']} {$user['lastname']}";
// ✅ NOTIFIER DIRECTION, DAF, SUPERADMIN DE TOUS LES STORES
if (is_array($allStores) && count($allStores) > 0) {
foreach ($allStores as $store) {
$Notification->createNotification( $Notification->createNotification(
"Commande validée par la caisse: {$bill_no}", $messageGlobal,
"Direction", "Direction",
(int)$user['store_id'], (int)$store['id'],
'orders'
);
$Notification->createNotification(
$messageGlobal,
"DAF",
(int)$store['id'],
'orders' 'orders'
); );
$Notification->createNotification(
$messageGlobal,
"SuperAdmin",
(int)$store['id'],
'orders'
);
}
} }
} }
@ -973,7 +1097,7 @@ public function update(int $id)
$html = ''; $html = '';
// Vérifier si l'utilisateur a payé // Vérifier si l'utilisateur a payé
if ($order_data['paid_status'] == 1) { if ($order_data['paid_status'] == 1) {
$paid_status = "<span style='color: green; font-weight: bold;'>Validé</span>"; $paid_status = "<span style='color: green; font-weight: bold;'>Payé</span>";
} elseif ($order_data['paid_status'] == 2) { } elseif ($order_data['paid_status'] == 2) {
$paid_status = "<span style='color: orange; font-weight: bold;'>En Attente</span>"; $paid_status = "<span style='color: orange; font-weight: bold;'>En Attente</span>";
} else { } else {
@ -1460,7 +1584,7 @@ public function update(int $id)
$company_info = $Company->getCompanyData(1); $company_info = $Company->getCompanyData(1);
$paid_status = $order_data['paid_status'] == 1 $paid_status = $order_data['paid_status'] == 1
? "<span style='color: green; font-weight: bold;'>Validé</span>" ? "<span style='color: green; font-weight: bold;'>Payé</span>"
: "<span style='color: red; font-weight: bold;'>Refusé</span>"; : "<span style='color: red; font-weight: bold;'>Refusé</span>";
// STYLE COMMUN // STYLE COMMUN
@ -2484,7 +2608,7 @@ public function print31(int $id)
} }
$paid_status = $order_data['paid_status'] === 1 $paid_status = $order_data['paid_status'] === 1
? "<span style='color: green; font-weight: bold;'>Validé</span>" ? "<span style='color: green; font-weight: bold;'>Payé</span>"
: "<span style='color: red; font-weight: bold;'>Refusé</span>"; : "<span style='color: red; font-weight: bold;'>Refusé</span>";
// Calculs globaux // Calculs globaux

171
app/Controllers/RecouvrementController.php

@ -7,6 +7,7 @@ use App\Models\Orders;
use App\Models\Recouvrement; use App\Models\Recouvrement;
use App\Models\SortieCaisse; use App\Models\SortieCaisse;
use App\Models\Avance; use App\Models\Avance;
use App\Models\Stores;
class RecouvrementController extends AdminController class RecouvrementController extends AdminController
{ {
@ -197,14 +198,61 @@ class RecouvrementController extends AdminController
$this->verifyRole('deleteRecouvrement'); $this->verifyRole('deleteRecouvrement');
$recouvrement_id = $this->request->getPost('recouvrement_id'); $recouvrement_id = $this->request->getPost('recouvrement_id');
$response = []; $response = [];
if ($recouvrement_id) { if ($recouvrement_id) {
$Recouvrement = new Recouvrement(); $Recouvrement = new Recouvrement();
// ✅ Récupérer les infos du recouvrement avant suppression
$recouvrementData = $Recouvrement->getRecouvrementSingle($recouvrement_id);
if ($Recouvrement->deleteRecouvrement($recouvrement_id)) { if ($Recouvrement->deleteRecouvrement($recouvrement_id)) {
// ✅ Notification pour TOUS les Direction, DAF et SuperAdmin de TOUS les stores
try {
if (class_exists('App\Controllers\NotificationController') && $recouvrementData) {
$Notification = new NotificationController();
$Stores = new Stores();
$allStores = $Stores->getActiveStore();
$session = session();
$users = $session->get('user');
$message = "🗑️ Recouvrement supprimé<br>" .
"Montant: " . number_format($recouvrementData['recouvrement_montant'], 0, ',', ' ') . " Ar<br>" .
"Par: " . $users['firstname'] . ' ' . $users['lastname'];
// ✅ Notifier Direction, DAF et SuperAdmin de TOUS les stores
if (is_array($allStores) && count($allStores) > 0) {
foreach ($allStores as $store) {
$Notification->createNotification(
$message,
"Direction",
(int)$store['id'],
'recouvrement'
);
$Notification->createNotification(
$message,
"DAF",
(int)$store['id'],
'recouvrement'
);
$Notification->createNotification(
$message,
"SuperAdmin",
(int)$store['id'],
'recouvrement'
);
}
}
}
} catch (\Exception $e) {
log_message('error', 'Erreur notification removeRecouvrement: ' . $e->getMessage());
}
$response['success'] = true; $response['success'] = true;
$response['messages'] = "Recouvrement supprimé avec succès !"; $response['messages'] = "Recouvrement supprimé avec succès !<br><em>Notification envoyée à tous les Direction, DAF et SuperAdmin</em>";
} else { } else {
$response['success'] = false; $response['success'] = false;
$response['messages'] = "Erreur lors de la suppression du recouvrement."; $response['messages'] = "Erreur lors de la suppression du recouvrement.";
@ -216,6 +264,7 @@ class RecouvrementController extends AdminController
return $this->response->setJSON($response); return $this->response->setJSON($response);
} }
public function createRecouvrement() public function createRecouvrement()
{ {
$this->verifyRole('createRecouvrement'); $this->verifyRole('createRecouvrement');
@ -272,9 +321,57 @@ class RecouvrementController extends AdminController
]; ];
if ($Recouvrement->addRecouvrement($data)) { if ($Recouvrement->addRecouvrement($data)) {
$Notification->createNotification("Un nouveau recouvrement a été crée", "Direction", (int)$users["store_id"], 'recouvrement'); // ✅ Notification pour TOUS les Direction, DAF et SuperAdmin de TOUS les stores
try {
if (class_exists('App\Controllers\NotificationController')) {
$Stores = new Stores();
$allStores = $Stores->getActiveStore();
$message = "💱 Nouveau recouvrement créé<br>" .
"Montant: " . number_format($amount, 0, ',', ' ') . " Ar<br>" .
"De: " . $send_mode . " → Vers: " . $get_mode . "<br>" .
"Store: " . $this->returnStoreName($users['store_id']) . "<br>" .
"Par: " . $fullname;
// ✅ Notifier Direction, DAF et SuperAdmin de TOUS les stores
if (is_array($allStores) && count($allStores) > 0) {
foreach ($allStores as $store) {
// Notifier Direction
$Notification->createNotification(
$message,
"Direction",
(int)$store['id'],
'recouvrement'
);
// Notifier DAF
$Notification->createNotification(
$message,
"DAF",
(int)$store['id'],
'recouvrement'
);
// Notifier SuperAdmin
$Notification->createNotification(
$message,
"SuperAdmin",
(int)$store['id'],
'recouvrement'
);
}
}
}
} catch (\Exception $e) {
log_message('error', 'Erreur notification createRecouvrement: ' . $e->getMessage());
// Continue même si la notification échoue
}
$response['success'] = true; $response['success'] = true;
$response['messages'] = 'Recouvrement créé avec succès'; $response['messages'] = 'Recouvrement créé avec succès<br>' .
'Montant: ' . number_format($amount, 0, ',', ' ') . ' Ar<br>' .
$send_mode . ' → ' . $get_mode . '<br>' .
'<em>Notification envoyée à tous les Direction, DAF et SuperAdmin</em>';
} else { } else {
$response['success'] = false; $response['success'] = false;
$response['messages'] = 'Erreur lors de la création du recouvrement.'; $response['messages'] = 'Erreur lors de la création du recouvrement.';
@ -288,7 +385,6 @@ class RecouvrementController extends AdminController
return $this->response->setJSON($response); return $this->response->setJSON($response);
} }
public function updateRecouvrement($recouvrement_id) public function updateRecouvrement($recouvrement_id)
{ {
$this->verifyRole('updateRecouvrement'); $this->verifyRole('updateRecouvrement');
@ -308,18 +404,61 @@ class RecouvrementController extends AdminController
]; ];
$Recouvrement = new Recouvrement(); $Recouvrement = new Recouvrement();
// $recouvrement_id = (int) $this->request->getPost('recouvrement_id');
if ($this->request->getMethod() === 'post') { if ($this->request->getMethod() === 'post') {
$data = [ $data = [
'recouvrement_montant' => (int) $this->request->getPost('recouvrement_montant_edit'), 'recouvrement_montant' => (int) $this->request->getPost('recouvrement_montant_edit'),
'recouvrement_date' => $this->request->getPost('recouvrement_date_edit') 'recouvrement_date' => $this->request->getPost('recouvrement_date_edit')
]; ];
if ($Recouvrement->updateRecouvrement($recouvrement_id, $data)) { if ($Recouvrement->updateRecouvrement($recouvrement_id, $data)) {
// $Notification->createNotification("Un nouveau recouvrement crée", "Conseil", $users['store_id'], 'recouvrement'); // ✅ Notification pour TOUS les Direction, DAF et SuperAdmin de TOUS les stores
try {
if (class_exists('App\Controllers\NotificationController')) {
$Notification = new NotificationController();
$Stores = new Stores();
$allStores = $Stores->getActiveStore();
$session = session();
$users = $session->get('user');
$message = "✏️ Recouvrement modifié<br>" .
"Nouveau montant: " . number_format($data['recouvrement_montant'], 0, ',', ' ') . " Ar<br>" .
"Par: " . $users['firstname'] . ' ' . $users['lastname'];
// ✅ Notifier Direction, DAF et SuperAdmin de TOUS les stores
if (is_array($allStores) && count($allStores) > 0) {
foreach ($allStores as $store) {
$Notification->createNotification(
$message,
"Direction",
(int)$store['id'],
'recouvrement'
);
$Notification->createNotification(
$message,
"DAF",
(int)$store['id'],
'recouvrement'
);
$Notification->createNotification(
$message,
"SuperAdmin",
(int)$store['id'],
'recouvrement'
);
}
}
}
} catch (\Exception $e) {
log_message('error', 'Erreur notification updateRecouvrement: ' . $e->getMessage());
}
return $this->response->setJSON([ return $this->response->setJSON([
'success' => true, 'success' => true,
'messages' => 'Recouvrement modifié avec succès !' 'messages' => 'Recouvrement modifié avec succès !<br><em>Notification envoyée à tous les Direction, DAF et SuperAdmin</em>'
]); ]);
} else { } else {
return $this->response->setJSON([ return $this->response->setJSON([
@ -340,6 +479,20 @@ class RecouvrementController extends AdminController
echo json_encode($data); echo json_encode($data);
} }
} }
private function returnStoreName(int $id): string
{
$Stores = new Stores();
$stor = $Stores->getActiveStore();
$Storename = "";
foreach ($stor as $key => $value) {
if ($value['id'] == $id) {
$Storename = $value['name'];
}
}
return $Storename;
}
private function canMakeRecouvrement($send_mode, $get_mode, $amount): bool private function canMakeRecouvrement($send_mode, $get_mode, $amount): bool
{ {
$orders = new Orders(); $orders = new Orders();

129
app/Controllers/RemiseController.php

@ -6,6 +6,7 @@ use App\Controllers\AdminController;
use App\Models\Notification; use App\Models\Notification;
use App\Models\Orders; use App\Models\Orders;
use App\Models\Remise; use App\Models\Remise;
use App\Models\Stores;
class RemiseController extends AdminController class RemiseController extends AdminController
{ {
@ -25,7 +26,6 @@ class RemiseController extends AdminController
$this->render_template('demande/index', $data); $this->render_template('demande/index', $data);
} }
public function fetchTotal(){ public function fetchTotal(){
$data = [ $data = [
'user_permission' => $this->permission, 'user_permission' => $this->permission,
@ -34,7 +34,6 @@ class RemiseController extends AdminController
return json_encode($data); return json_encode($data);
} }
public function fetchRemiseData() public function fetchRemiseData()
{ {
helper(['url', 'form']); helper(['url', 'form']);
@ -50,21 +49,31 @@ class RemiseController extends AdminController
"recordsFiltered" => $totalRecords, "recordsFiltered" => $totalRecords,
"data" => [] "data" => []
]; ];
// ✅ RÉCUPÉRER LE RÔLE DE L'UTILISATEUR
$session = session();
$user = $session->get('user');
$role = $user['group_name'] ?? '';
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
$buttons = ''; $buttons = '';
if (in_array('validateRemise', $this->permission) && $value['demande_status'] == 'En attente') { // ✅ SEUL LE SUPERADMIN PEUT VALIDER/REFUSER
if ($role === 'SuperAdmin' && $value['demande_status'] == 'En attente') {
$buttons .= '<button type="submit" class="btn btn-success" onclick="valideFunc(' . $value['id_demande'] . ')">'; $buttons .= '<button type="submit" class="btn btn-success" onclick="valideFunc(' . $value['id_demande'] . ')">';
$buttons .= '<i class="fa fa-check-circle"></i>'; $buttons .= '<i class="fa fa-check-circle"></i>';
$buttons .= '</button>'; $buttons .= '</button>';
}
if (in_array('refusedRemise', $this->permission) && $value['demande_status'] == 'En attente') {
$buttons .= ' <button type="button" class="btn btn-danger" onclick="refuseFunc(' . $value['id_demande'] . ')">'; $buttons .= ' <button type="button" class="btn btn-danger" onclick="refuseFunc(' . $value['id_demande'] . ')">';
$buttons .= '<i class="fa fa-times-circle"></i>'; $buttons .= '<i class="fa fa-times-circle"></i>';
$buttons .= '</button>'; $buttons .= '</button>';
} }
// ✅ DIRECTION ET DAF VOIENT SEULEMENT (pas de boutons d'action)
if (in_array($role, ['Direction', 'DAF'])) {
$buttons = '<span class="label label-info">Consultation uniquement</span>';
}
$result['data'][$key] = [ $result['data'][$key] = [
$value['id_demande'], $value['id_demande'],
$value['product'], $value['product'],
@ -78,9 +87,23 @@ class RemiseController extends AdminController
return $this->response->setJSON($result); return $this->response->setJSON($result);
} }
/**
* ✅ AMÉLIORATION : Notifications centralisées lors de la validation/refus des remises
*/
public function updateRemise($id_demande) public function updateRemise($id_demande)
{ {
// ✅ VÉRIFIER QUE SEUL LE SUPERADMIN PEUT VALIDER
$session = session();
$user = $session->get('user');
$role = $user['group_name'] ?? '';
if ($role !== 'SuperAdmin') {
return $this->response->setJSON([
'success' => false,
'messages' => 'Seul le SuperAdmin peut valider ou refuser les demandes de remise.'
]);
}
$this->verifyRole('validateRemise'); $this->verifyRole('validateRemise');
$validation = \Config\Services::validation(); $validation = \Config\Services::validation();
@ -108,44 +131,104 @@ class RemiseController extends AdminController
if ($Remise->updateRemise($id_demande, $data)) { if ($Remise->updateRemise($id_demande, $data)) {
$remise_product = $Remise->getProductByDemandeId($id_demande); $remise_product = $Remise->getProductByDemandeId($id_demande);
$Notification = new NotificationController(); $Notification = new NotificationController();
$session = session();
$users = $session->get('user');
$ordersModel = new Orders(); $ordersModel = new Orders();
$order_id = $Remise->getOrderIdByDemandeId($id_demande); $order_id = $Remise->getOrderIdByDemandeId($id_demande);
// Logique de notification selon le statut // ✅ Récupérer les infos de la commande
$order_info = $ordersModel->getOrdersData($order_id);
$bill_no = $order_info['bill_no'] ?? '';
$store_id = $order_info['store_id'] ?? 0;
// ✅ RÉCUPÉRER TOUS LES STORES
$Stores = new Stores();
$allStores = $Stores->getActiveStore();
// ✅ SI REFUSÉ PAR LE SUPERADMIN
if ($demande_status == 'Refusé') { if ($demande_status == 'Refusé') {
// Mettre à jour le paid_status de la commande à 0 (Refusé)
if ($order_id) { if ($order_id) {
$ordersModel->update($order_id, ['paid_status' => 0]); $ordersModel->update($order_id, ['paid_status' => 0]);
} }
// Si refusé par le Conseil : notification retourne au Commercial // Message de refus
$messageRefus = "❌ Demande de remise refusée : {$bill_no}<br>" .
"Produit : {$remise_product}<br>" .
"Décision : SuperAdmin";
// Notifier le commercial du store concerné
$Notification->createNotification( $Notification->createNotification(
"Votre demande de remise a été refusée pour le produit: " . $remise_product . ". Veuillez modifier la commande.", $messageRefus . "<br><em>Veuillez modifier la commande.</em>",
"COMMERCIALE", "COMMERCIALE",
(int)$users['store_id'], (int)$store_id,
"orders" // Retour à l'ajout de commande chez le commercial "orders"
); );
$message = 'La demande de remise a été refusée. Une notification a été envoyée au commercial.'; // ✅ NOTIFIER DIRECTION ET DAF DE TOUS LES STORES (POUR INFORMATION)
if (is_array($allStores) && count($allStores) > 0) {
foreach ($allStores as $store) {
$Notification->createNotification(
$messageRefus . "<br><em>Pour information</em>",
"Direction",
(int)$store['id'],
'remise/'
);
$Notification->createNotification(
$messageRefus . "<br><em>Pour information</em>",
"DAF",
(int)$store['id'],
'remise/'
);
}
}
$message = 'La demande de remise a été refusée. Le commercial et les responsables ont été notifiés.';
} elseif ($demande_status == 'Accepté' || $demande_status == 'Validé') { } elseif ($demande_status == 'Accepté' || $demande_status == 'Validé') {
// Si accepté par le Conseil : la commande reste "En Attente" (paid_status = 2) // ✅ SI ACCEPTÉ PAR LE SUPERADMIN
// La caissière devra la valider manuellement
if ($order_id) { if ($order_id) {
$ordersModel->update($order_id, ['paid_status' => 2]); // 2 = En Attente $ordersModel->update($order_id, ['paid_status' => 2]);
} }
// Notification à la Caissière pour qu'elle valide la commande $messageAcceptation = "✅ Demande de remise acceptée : {$bill_no}<br>" .
"Produit : {$remise_product}<br>" .
"Décision : SuperAdmin";
// Notifier la Caissière du store concerné
$Notification->createNotification( $Notification->createNotification(
"Une commande avec remise acceptée est prête pour validation. Produit: " . $remise_product, $messageAcceptation . "<br><em>Commande prête à être traitée</em>",
"Caissière", "Caissière",
(int)$users['store_id'], (int)$store_id,
"orders" // Va chez la caissière pour validation finale "orders"
);
// Notifier le commercial du store concerné
$Notification->createNotification(
$messageAcceptation,
"COMMERCIALE",
(int)$store_id,
"orders"
);
// ✅ NOTIFIER DIRECTION ET DAF DE TOUS LES STORES (POUR INFORMATION)
if (is_array($allStores) && count($allStores) > 0) {
foreach ($allStores as $store) {
$Notification->createNotification(
$messageAcceptation . "<br><em>Pour information</em>",
"Direction",
(int)$store['id'],
'remise/'
); );
$message = 'La demande de remise a été acceptée. La commande a été envoyée à la caissière pour validation.'; $Notification->createNotification(
$messageAcceptation . "<br><em>Pour information</em>",
"DAF",
(int)$store['id'],
'remise/'
);
}
}
$message = 'La demande de remise a été acceptée. La caissière, le commercial et les responsables ont été notifiés.';
} }
return $this->response->setJSON([ return $this->response->setJSON([

2
app/Controllers/ReportController.php

@ -262,7 +262,7 @@ class ReportController extends AdminController
$users = $session->get('user'); $users = $session->get('user');
// Pour Direction et Conseil : afficher TOUTES les performances // Pour Direction et Conseil : afficher TOUTES les performances
if ($users['group_name'] === "DAF" || $users['group_name'] === "Direction") { if ($users['group_name'] === "DAF" || $users['group_name'] === "Direction" ||$users['group_name'] === "SuperAdmin" ) {
$orderPaid = $Orders->getPerformanceByOrders(); $orderPaid = $Orders->getPerformanceByOrders();
foreach ($orderPaid as $key => $value) { foreach ($orderPaid as $key => $value) {
// Déterminer le prix de vente réel // Déterminer le prix de vente réel

199
app/Controllers/SortieCaisseController.php

@ -22,6 +22,87 @@ class SortieCaisseController extends AdminController
} }
private $mapping = [ private $mapping = [
// superadmin
"Achat de matériel informatique" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Achat équipement de sécurité" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Achat mobilier de bureau" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Paiement salaire des collaborateurs" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Cotisation sociales" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Remboursement d'avance moto" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Payement prime ou endemnité" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Paiement sous-traitant" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Frais de formation" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Paiement loyer" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Frais de formation externe" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Abonnement internet" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Entretien locaux" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Paiement fournisseur" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Remboursement de frais" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Paiement assurance" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Réparation immobilisation" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"DVD" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Déclaration fiscale - Déclaration d'impôts" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
"Enregistrement des contrats de bail au centre fiscal" => [
'source_fond' => 'Budget Directionnel',
'initiateur_demande' => 'SuperAdmin'
],
// ----- Raisons Admin ----- // ----- Raisons Admin -----
"Achat de matériel informatique" => [ "Achat de matériel informatique" => [
'source_fond' => 'Budget Directionnel', 'source_fond' => 'Budget Directionnel',
@ -243,7 +324,7 @@ class SortieCaisseController extends AdminController
$users = $session->get('user'); $users = $session->get('user');
// ✅ Vérifier si l'utilisateur est DAF ou Direction UNIQUEMENT // ✅ Vérifier si l'utilisateur est DAF ou Direction UNIQUEMENT
$canManage = in_array($users['group_name'], ['Direction', 'DAF']); $canManage = in_array($users['group_name'], ['Direction', 'DAF','SuperAdmin']);
$isCaissiere = $users['group_name'] === 'Caissière'; $isCaissiere = $users['group_name'] === 'Caissière';
$result = [ $result = [
@ -289,7 +370,7 @@ class SortieCaisseController extends AdminController
$buttons // Les caissières ne verront PAS les boutons (car $canManage = false) $buttons // Les caissières ne verront PAS les boutons (car $canManage = false)
]; ];
} }
elseif ($users["group_name"] === "Direction" || $users["group_name"] === "DAF") { elseif ($users["group_name"] === "Direction" || $users["group_name"] === "DAF" ||$users["group_name"] === "SuperAdmin" ) {
$result['data'][$key] = [ $result['data'][$key] = [
$value['id_sortie'], $value['id_sortie'],
number_format($value['montant_retire'], 0, '.', ' '), number_format($value['montant_retire'], 0, '.', ' '),
@ -328,8 +409,12 @@ class SortieCaisseController extends AdminController
* ✅ NOUVELLE MÉTHODE : Marquer un décaissement comme payé * ✅ NOUVELLE MÉTHODE : Marquer un décaissement comme payé
* Accessible uniquement par les caissières * Accessible uniquement par les caissières
*/ */
public function markAsPaid($id_sortie) /**
{ * ✅ CORRECTION COMPLÈTE : Marquer un décaissement comme payé
* Accessible uniquement par les caissières
*/
public function markAsPaid($id_sortie)
{
// Vérifier que l'utilisateur est une caissière // Vérifier que l'utilisateur est une caissière
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
@ -371,7 +456,8 @@ class SortieCaisseController extends AdminController
$result = $SortieCaisse->updateSortieCaisse($id_sortie, $data); $result = $SortieCaisse->updateSortieCaisse($id_sortie, $data);
if ($result) { if ($result) {
// Créer une notification pour DAF et Direction DU MÊME STORE // ✅ Créer une notification pour TOUS les DAF, Direction et SuperAdmin
try {
if (class_exists('App\Controllers\NotificationController')) { if (class_exists('App\Controllers\NotificationController')) {
$Notification = new NotificationController(); $Notification = new NotificationController();
@ -379,29 +465,50 @@ class SortieCaisseController extends AdminController
$message = "💰 Décaissement payé - " . $montant . " Ar<br>" . $message = "💰 Décaissement payé - " . $montant . " Ar<br>" .
"Motif: " . $decaissement['motif'] . "<br>" . "Motif: " . $decaissement['motif'] . "<br>" .
"Caissière: " . $users['firstname'] . ' ' . $users['lastname'] . "<br>" . "Caissière: " . $users['firstname'] . ' ' . $users['lastname'] . "<br>" .
"Store: " . $this->returnStoreName($users['store_id']); "Store: " . $this->returnStoreName($decaissement['store_id']);
// ✅ Notifier la Direction DU MÊME STORE // ✅ Récupérer TOUS les stores
$Stores = new Stores();
$allStores = $Stores->getActiveStore();
// ✅ Notifier Direction, DAF et SuperAdmin de TOUS les stores
if (is_array($allStores) && count($allStores) > 0) {
foreach ($allStores as $store) {
// Notifier Direction
$Notification->createNotification( $Notification->createNotification(
$message, $message,
"Direction", "Direction",
(int)$users['store_id'], // ✅ Store ID de la caissière (int)$store['id'],
'sortieCaisse' 'sortieCaisse'
); );
// Notifier le DAF DU MÊME STORE // Notifier DAF
$Notification->createNotification( $Notification->createNotification(
$message, $message,
"DAF", "DAF",
(int)$users['store_id'], // ✅ Store ID de la caissière (int)$store['id'],
'sortieCaisse'
);
// Notifier SuperAdmin
$Notification->createNotification(
$message,
"SuperAdmin",
(int)$store['id'],
'sortieCaisse' 'sortieCaisse'
); );
} }
}
}
} catch (\Exception $e) {
// Logger l'erreur mais continuer
log_message('error', 'Erreur notification markAsPaid: ' . $e->getMessage());
}
return $this->response->setJSON([ return $this->response->setJSON([
'success' => true, 'success' => true,
'messages' => '✅ Décaissement marqué comme <strong>PAYÉ</strong><br>' . 'messages' => '✅ Décaissement marqué comme <strong>PAYÉ</strong><br>' .
'Direction et DAF de ' . $this->returnStoreName($users['store_id']) . ' ont été notifiés.<br>' . 'Tous les Direction, DAF et SuperAdmin ont été notifiés.<br>' .
'Montant: ' . number_format($decaissement['montant_retire'], 0, ',', ' ') . ' Ar' 'Montant: ' . number_format($decaissement['montant_retire'], 0, ',', ' ') . ' Ar'
]); ]);
@ -413,14 +520,13 @@ class SortieCaisseController extends AdminController
} }
} catch (\Exception $e) { } catch (\Exception $e) {
log_message('error', 'Erreur markAsPaid: ' . $e->getMessage()); log_message('error', 'Erreur markAsPaid: ' . $e->getMessage() . ' | Ligne: ' . $e->getLine());
return $this->response->setJSON([ return $this->response->setJSON([
'success' => false, 'success' => false,
'messages' => 'Erreur serveur: ' . $e->getMessage() 'messages' => 'Erreur serveur: ' . $e->getMessage()
]); ]);
} }
} }
public function fetchSortieCaisseData1() public function fetchSortieCaisseData1()
{ {
helper(['url', 'form']); helper(['url', 'form']);
@ -436,7 +542,7 @@ class SortieCaisseController extends AdminController
$users = $session->get('user'); $users = $session->get('user');
// ✅ Vérifier si l'utilisateur est DAF ou Direction UNIQUEMENT // ✅ Vérifier si l'utilisateur est DAF ou Direction UNIQUEMENT
$canManage = in_array($users['group_name'], ['Direction', 'DAF']); $canManage = in_array($users['group_name'], ['Direction', 'DAF','SuperAdmin']);
$isCaissiere = $users['group_name'] === 'Caissière'; $isCaissiere = $users['group_name'] === 'Caissière';
$result = [ $result = [
@ -481,7 +587,7 @@ class SortieCaisseController extends AdminController
$buttons // Les caissières ne verront PAS les boutons $buttons // Les caissières ne verront PAS les boutons
]; ];
} }
elseif ($users["group_name"] === "Direction" || $users["group_name"] === "DAF") { elseif ($users["group_name"] === "Direction" || $users["group_name"] === "DAF" || $users["group_name"] === "SuperAdmin") {
$result['data'][$key] = [ $result['data'][$key] = [
$value['id_sortie'], $value['id_sortie'],
number_format($value['montant_retire'], 0, '.', ' '), number_format($value['montant_retire'], 0, '.', ' '),
@ -591,10 +697,10 @@ class SortieCaisseController extends AdminController
} }
// Recouvrements // Recouvrements
$total_recouvrement_me = 0; // Mvola -> Espèce $total_recouvrement_me = 0;
$total_recouvrement_be = 0; // Banque -> Espèce $total_recouvrement_be = 0;
$total_recouvrement_bm = 0; // Banque -> Mvola $total_recouvrement_bm = 0;
$total_recouvrement_mb = 0; // Mvola -> Banque $total_recouvrement_mb = 0;
if (is_object($totalRecouvrement)) { if (is_object($totalRecouvrement)) {
$total_recouvrement_me = isset($totalRecouvrement->me) ? (float) $totalRecouvrement->me : 0; $total_recouvrement_me = isset($totalRecouvrement->me) ? (float) $totalRecouvrement->me : 0;
@ -621,14 +727,12 @@ class SortieCaisseController extends AdminController
} }
// CALCUL DES SOLDES DISPONIBLES PAR MODE DE PAIEMENT // CALCUL DES SOLDES DISPONIBLES PAR MODE DE PAIEMENT
// Espèce: Orders + Recouvrements entrants - Sorties en espèce
$total_espece_disponible = $total_espece1 + $total_espece_disponible = $total_espece1 +
$total_espece2 + $total_espece2 +
$total_recouvrement_me + $total_recouvrement_me +
$total_recouvrement_be - $total_recouvrement_be -
$total_sortie_espece; $total_sortie_espece;
// MVOLA: Orders - Recouvrements sortants + Recouvrements entrants - Sorties MVOLA
$total_mvola_disponible = $total_mvola1 + $total_mvola_disponible = $total_mvola1 +
$total_mvola2 - $total_mvola2 -
$total_recouvrement_me - $total_recouvrement_me -
@ -636,7 +740,6 @@ class SortieCaisseController extends AdminController
$total_recouvrement_bm - $total_recouvrement_bm -
$total_sortie_mvola; $total_sortie_mvola;
// Virement: Orders - Recouvrements sortants + Recouvrements entrants - Sorties virement
$total_virement_disponible = $total_virement1 + $total_virement_disponible = $total_virement1 +
$total_virement2 - $total_virement2 -
$total_recouvrement_be - $total_recouvrement_be -
@ -742,8 +845,8 @@ class SortieCaisseController extends AdminController
$data['date_visa_chef_service'] = $this->request->getPost('date_visa_chef_service') ?? null; $data['date_visa_chef_service'] = $this->request->getPost('date_visa_chef_service') ?? null;
$data['visa_direction'] = $this->request->getPost('visa_direction') ?? ''; $data['visa_direction'] = $this->request->getPost('visa_direction') ?? '';
$data['date_visa_direction'] = $this->request->getPost('date_visa_direction') ?? null; $data['date_visa_direction'] = $this->request->getPost('date_visa_direction') ?? null;
$data['visa_conseil'] = $this->request->getPost('visa_conseil') ?? ''; $data['visa_superAdmin'] = $this->request->getPost('visa_superAdmin') ?? '';
$data['date_visa_conseil'] = $this->request->getPost('date_visa_conseil') ?? null; $data['date_visa_superAdmin'] = $this->request->getPost('date_visa_superAdmin') ?? null;
$data['observations'] = $this->request->getPost('observations') ?? ''; $data['observations'] = $this->request->getPost('observations') ?? '';
} }
@ -767,33 +870,57 @@ class SortieCaisseController extends AdminController
$result = $model->addSortieCaisse($data); $result = $model->addSortieCaisse($data);
if ($result) { if ($result) {
// Notification UNIQUEMENT pour la Direction du même store // ✅ Notification pour TOUS les Direction, DAF et SuperAdmin
try {
if (class_exists('App\Controllers\NotificationController')) { if (class_exists('App\Controllers\NotificationController')) {
$Notification = new NotificationController(); $Notification = new NotificationController();
// ✅ Notifier UNIQUEMENT la Direction du store concerné $message = "Nouvelle demande de décaissement de " .
number_format($montant_retire, 0, ',', ' ') . " Ar (" . $mode_paiement . ")<br>" .
"Store: " . $this->returnStoreName($user['store_id']) . "<br>" .
"Demandeur: " . $user['firstname'] . ' ' . $user['lastname'];
// ✅ Récupérer TOUS les stores
$Stores = new Stores();
$allStores = $Stores->getActiveStore();
// ✅ Notifier Direction, DAF et SuperAdmin de TOUS les stores
if (is_array($allStores) && count($allStores) > 0) {
foreach ($allStores as $store) {
$Notification->createNotification( $Notification->createNotification(
"Nouvelle demande de décaissement de " . number_format($montant_retire, 0, ',', ' ') . " Ar (" . $mode_paiement . ")", $message,
"Direction", "Direction",
(int)$user['store_id'], // ✅ Store ID du créateur (int)$store['id'],
'sortieCaisse' 'sortieCaisse'
); );
// ✅ Notifier aussi le DAF du même store (si vous avez des DAF par store)
$Notification->createNotification( $Notification->createNotification(
"Nouvelle demande de décaissement de " . number_format($montant_retire, 0, ',', ' ') . " Ar (" . $mode_paiement . ")", $message,
"DAF", "DAF",
(int)$user['store_id'], // ✅ Store ID du créateur (int)$store['id'],
'sortieCaisse'
);
$Notification->createNotification(
$message,
"SuperAdmin",
(int)$store['id'],
'sortieCaisse' 'sortieCaisse'
); );
} }
}
}
} catch (\Exception $e) {
log_message('error', 'Erreur notification createSortieCaisse: ' . $e->getMessage());
// Continue même si la notification échoue
}
return $this->response->setJSON([ return $this->response->setJSON([
'success' => true, 'success' => true,
'messages' => 'Décaissement de ' . number_format($montant_retire, 0, ',', ' ') . ' Ar créé avec succès<br>' . 'messages' => 'Décaissement de ' . number_format($montant_retire, 0, ',', ' ') . ' Ar créé avec succès<br>' .
'Mode de paiement: ' . $mode_paiement . '<br>' . 'Mode de paiement: ' . $mode_paiement . '<br>' .
'Nouveau solde ' . $mode_paiement_label . ': ' . number_format($fonds_disponible - $montant_retire, 0, ',', ' ') . ' Ar<br>' . 'Nouveau solde ' . $mode_paiement_label . ': ' . number_format($fonds_disponible - $montant_retire, 0, ',', ' ') . ' Ar<br>' .
'<em>Notification envoyée à la Direction de ' . $this->returnStoreName($user['store_id']) . '</em>' '<em>Notification envoyée à tous les Direction, DAF et SuperAdmin</em>'
]); ]);
} else { } else {
@ -1096,15 +1223,15 @@ class SortieCaisseController extends AdminController
switch ($statut) { switch ($statut) {
case "Valider": case "Valider":
$message = "✅ Votre décaissement a été validé par la Direction de " . $this->returnStoreName($store_id); $message = "✅ Votre décaissement a été validé par la Direction<br>Store: " . $this->returnStoreName($store_id);
$Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse'); $Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse');
break; break;
case "Refuser": case "Refuser":
$message = "❌ Votre décaissement a été refusé par la Direction de " . $this->returnStoreName($store_id) . "<br>Raison: " . $this->request->getPost('admin_raison'); $message = "❌ Votre décaissement a été refusé par la Direction<br>Store: " . $this->returnStoreName($store_id) . "<br>Raison: " . $this->request->getPost('admin_raison');
$Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse'); $Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse');
break; break;
case "En attente": case "En attente":
$message = "⏳ Votre décaissement a été mis en attente par la Direction de " . $this->returnStoreName($store_id); $message = "⏳ Votre décaissement a été mis en attente par la Direction<br>Store: " . $this->returnStoreName($store_id);
$Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse'); $Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse');
break; break;
} }

2
app/Controllers/StatistiqueController.php

@ -78,7 +78,7 @@ class StatistiqueController extends AdminController
// echo '</pre>'; // echo '</pre>';
$data['is_admin'] = false; $data['is_admin'] = false;
if ($user_id['group_name'] == "Direction" || $user_id['group_name'] == "Conseil") { if ($user_id['group_name'] == "Direction" || $user_id['group_name'] == "SuperAdmin") {
$data['is_admin'] = true; $data['is_admin'] = true;
} }

95
app/Models/Avance.php

@ -58,7 +58,7 @@ class Avance extends Model {
public function getAllAvanceData(int $id=null) { public function getAllAvanceData(int $id=null) {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction','DAF']);
if($isAdmin) { if($isAdmin) {
if($id){ if($id){
try { try {
@ -125,7 +125,7 @@ class Avance extends Model {
public function getTotalAvance() { public function getTotalAvance() {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction','DAF']);
try { try {
$builder = $this->select('SUM(avance_amount) AS ta') $builder = $this->select('SUM(avance_amount) AS ta')
@ -148,7 +148,7 @@ class Avance extends Model {
{ {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction','DAF']);
try { try {
$builder = $this->db->table('avances') $builder = $this->db->table('avances')
@ -194,7 +194,7 @@ class Avance extends Model {
public function getAllAvanceData1(int $id=null) { public function getAllAvanceData1(int $id=null) {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction','DAF']);
if($isAdmin) { if($isAdmin) {
if($id){ if($id){
try { try {
@ -249,7 +249,7 @@ class Avance extends Model {
public function getAllAvanceData2(int $id=null) { public function getAllAvanceData2(int $id=null) {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
if($isAdmin) { if($isAdmin) {
if($id){ if($id){
try { try {
@ -336,7 +336,7 @@ class Avance extends Model {
{ {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
$builder = $this->where('is_order', 0) $builder = $this->where('is_order', 0)
->where('active', 1) ->where('active', 1)
@ -357,7 +357,7 @@ class Avance extends Model {
{ {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
$builder = $this->where('is_order', 0) $builder = $this->where('is_order', 0)
->where('active', 1) ->where('active', 1)
@ -451,7 +451,7 @@ public function convertToOrder(int $avance_id)
return false; return false;
} }
// ✅ MODIFICATION PRINCIPALE : Vérifier que c'est bien une avance sur TERRE // ✅ Vérifier que c'est bien une avance sur TERRE
if ($avance['type_avance'] !== 'terre') { if ($avance['type_avance'] !== 'terre') {
log_message('info', "Avance {$avance_id} de type '{$avance['type_avance']}' - Conversion ignorée (seules les avances TERRE sont converties)"); log_message('info', "Avance {$avance_id} de type '{$avance['type_avance']}' - Conversion ignorée (seules les avances TERRE sont converties)");
return false; return false;
@ -528,9 +528,6 @@ public function convertToOrder(int $avance_id)
]); ]);
log_message('info', "Item ajouté : produit {$avance['product_id']} (TERRE)"); log_message('info', "Item ajouté : produit {$avance['product_id']} (TERRE)");
// ✅ Le produit reste marqué comme vendu (product_sold = 1)
// Il sera géré dans la commande maintenant
} else { } else {
log_message('warning', "Produit {$avance['product_id']} introuvable pour avance TERRE {$avance_id}"); log_message('warning', "Produit {$avance['product_id']} introuvable pour avance TERRE {$avance_id}");
} }
@ -538,7 +535,7 @@ public function convertToOrder(int $avance_id)
// ✅ 3. Marquer l'avance comme convertie // ✅ 3. Marquer l'avance comme convertie
$this->update($avance_id, [ $this->update($avance_id, [
'is_order' => 1, 'is_order' => 1,
'active' => 0, // Désactiver l'avance (elle devient commande) 'active' => 0,
]); ]);
$db->transComplete(); $db->transComplete();
@ -548,7 +545,10 @@ public function convertToOrder(int $avance_id)
return false; return false;
} }
// ✅ 4. Notification à la caissière // ✅ 4. NOUVEAU : Envoyer notifications à TOUS les stores
$this->sendConversionNotifications($avance, $order_id, $bill_no);
// ✅ 5. Notification à la caissière du store concerné
$notificationController = new \App\Controllers\NotificationController(); $notificationController = new \App\Controllers\NotificationController();
$notificationController->createNotification( $notificationController->createNotification(
"Nouvelle commande issue d'une avance TERRE complète - {$bill_no}", "Nouvelle commande issue d'une avance TERRE complète - {$bill_no}",
@ -567,6 +567,70 @@ public function convertToOrder(int $avance_id)
} }
} }
private function sendConversionNotifications($avance, $order_id, $bill_no)
{
try {
$Notification = new \App\Controllers\NotificationController();
$db = \Config\Database::connect();
// Récupérer tous les stores
$storesQuery = $db->table('stores')->select('id')->get();
$allStores = $storesQuery->getResultArray();
// Récupérer les infos de l'utilisateur
$userQuery = $db->table('users')
->select('firstname, lastname')
->where('id', $avance['user_id'])
->get();
$user = $userQuery->getRowArray();
$userName = $user ? "{$user['firstname']} {$user['lastname']}" : 'Utilisateur inconnu';
// Préparer le message
$customerName = $avance['customer_name'];
$avanceNumber = str_pad($avance['avance_id'], 5, '0', STR_PAD_LEFT);
$avanceAmount = number_format((float)$avance['gross_amount'], 0, ',', ' ');
$typeAvance = strtoupper($avance['type_avance']);
$notificationMessage = "🎉 Avance {$typeAvance} N°{$avanceNumber} convertie en COMMANDE {$bill_no} - Client: {$customerName} - Montant: {$avanceAmount} Ar - Par: {$userName}";
// ✅ Envoyer notification à DAF, Direction et SuperAdmin de TOUS les stores
foreach ($allStores as $store) {
$storeId = (int)$store['id'];
// Notification pour DAF
$Notification->createNotification(
$notificationMessage,
"DAF",
$storeId,
'orders'
);
// Notification pour Direction
$Notification->createNotification(
$notificationMessage,
"Direction",
$storeId,
'orders'
);
// Notification pour SuperAdmin
$Notification->createNotification(
$notificationMessage,
"SuperAdmin",
$storeId,
'orders'
);
}
log_message('info', "✅ Notifications conversion envoyées pour avance {$avance['avance_id']} → commande {$order_id} à tous les stores");
} catch (\Exception $e) {
log_message('error', "Erreur envoi notifications conversion: " . $e->getMessage());
}
}
/** /**
* ✅ Hook appelé automatiquement lors du paiement d'une avance * ✅ Hook appelé automatiquement lors du paiement d'une avance
* Intégrer ceci dans votre fonction de paiement existante * Intégrer ceci dans votre fonction de paiement existante
@ -631,6 +695,7 @@ public function afterPayment(int $avance_id)
->findAll(); ->findAll();
} }
/** /**
* ✅ NOUVELLE MÉTHODE : Récupérer les avances MER complètes (pour statistiques) * ✅ NOUVELLE MÉTHODE : Récupérer les avances MER complètes (pour statistiques)
*/ */
@ -638,7 +703,7 @@ public function afterPayment(int $avance_id)
{ {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
$builder = $this->where('amount_due', 0) $builder = $this->where('amount_due', 0)
->where('active', 1) ->where('active', 1)
@ -651,4 +716,6 @@ public function afterPayment(int $avance_id)
return $builder->orderBy('avance_date', 'DESC')->findAll(); return $builder->orderBy('avance_date', 'DESC')->findAll();
} }
} }

2
app/Models/Mecanicien.php

@ -24,7 +24,7 @@ class Mecanicien extends Model
{ {
$session = session(); $session = session();
$user = $session->get('user'); $user = $session->get('user');
if ($user['group_name'] == "Conseil" || $user['group_name'] == "Direction") { if ($user['group_name'] == "SuperAdmin" || $user['group_name'] == "Direction") {
$reparation = $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.*') $reparation = $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.*')
->join('users', 'reparations.user_id = users.id') ->join('users', 'reparations.user_id = users.id')
->join('products', 'reparations.produit_id = products.id') ->join('products', 'reparations.produit_id = products.id')

8
app/Models/Orders.php

@ -130,7 +130,7 @@ class Orders extends Model
$groupName = $group['group_name'] ?? ''; $groupName = $group['group_name'] ?? '';
// Selon le rôle // Selon le rôle
if (in_array($groupName, ['Direction', 'Conseil'], true)) { if (in_array($groupName, ['Direction', 'SuperAdmin', 'DAF'], true)) {
return $builder return $builder
->orderBy('orders.id', 'DESC') ->orderBy('orders.id', 'DESC')
->get() ->get()
@ -163,7 +163,7 @@ class Orders extends Model
$group = $this->getUserGroupNameByUserId($users['id']); $group = $this->getUserGroupNameByUserId($users['id']);
$groupName = $group['group_name'] ?? ''; // Évite une erreur si 'group_name' est null $groupName = $group['group_name'] ?? ''; // Évite une erreur si 'group_name' est null
if ($groupName === "Direction" || $groupName === "Conseil") { if ($groupName === "Direction" || $groupName === "SuperAdmin" || $groupName === "DAF") {
return $builder->orderBy('orders.id', 'DESC')->get()->getResultArray(); return $builder->orderBy('orders.id', 'DESC')->get()->getResultArray();
} else { } else {
return $builder->where('orders.store_id', $users['store_id']) return $builder->where('orders.store_id', $users['store_id'])
@ -369,7 +369,7 @@ class Orders extends Model
{ {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
if($isAdmin) { if($isAdmin) {
return $this->whereIn('paid_status', [1, 3]) // ← Ajoutez 3 ici return $this->whereIn('paid_status', [1, 3]) // ← Ajoutez 3 ici
@ -396,7 +396,7 @@ class Orders extends Model
{ {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
$baseQuery = $this->db->table('orders') $baseQuery = $this->db->table('orders')
->select(' ->select('

4
app/Models/Products.php

@ -21,7 +21,7 @@ class Products extends Model
$user = $session->get('user'); $user = $session->get('user');
// Vérifier si l'utilisateur est admin (Conseil ou Direction) // Vérifier si l'utilisateur est admin (Conseil ou Direction)
$isAdmin = in_array($user['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($user['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
$builder = $this->where('is_piece', 0) $builder = $this->where('is_piece', 0)
->where('product_sold', 0); ->where('product_sold', 0);
@ -206,7 +206,7 @@ public function countProductsByUserStore()
$user = $session->get('user'); $user = $session->get('user');
// Vérifier si l'utilisateur est admin // Vérifier si l'utilisateur est admin
$isAdmin = in_array($user['group_name'], ['DAF', 'Direction']); $isAdmin = in_array($user['group_name'], ['DAF', 'Direction', 'SuperAdmin']);
$db = \Config\Database::connect(); $db = \Config\Database::connect();

4
app/Models/Recouvrement.php

@ -73,7 +73,7 @@ class Recouvrement extends Model{
public function getTotalRecouvrements(int $id = null, $start_date = null, $end_date = null) { public function getTotalRecouvrements(int $id = null, $start_date = null, $end_date = null) {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['DAF', 'Direction']); $isAdmin = in_array($users['group_name'], ['DAF', 'Direction', 'SuperAdmin']);
if($isAdmin){ if($isAdmin){
if ($id) { if ($id) {
return $this->db->table('recouvrement') return $this->db->table('recouvrement')
@ -190,7 +190,7 @@ class Recouvrement extends Model{
{ {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['DAF', 'Direction']); $isAdmin = in_array($users['group_name'], ['DAF', 'Direction', 'SuperAdmin']);
$builder = $this->db->table('recouvrement'); $builder = $this->db->table('recouvrement');

26
app/Models/Remise.php

@ -6,10 +6,6 @@ use DateTime;
class Remise extends Model class Remise extends Model
{ {
/**
* table name
* @var string
*/
protected $table = 'demande_remise'; protected $table = 'demande_remise';
protected $primaryKey = 'id_demande'; protected $primaryKey = 'id_demande';
protected $allowedFields = ['id_order', 'montant_demande', 'date_demande','product','id_store','demande_status','total_price']; protected $allowedFields = ['id_order', 'montant_demande', 'date_demande','product','id_store','demande_status','total_price'];
@ -20,26 +16,26 @@ class Remise extends Model
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
// Si le rôle est CONSEIL → voir toutes les demandes "En attente" // ✅ SUPERADMIN VOIT TOUTES LES DEMANDES "EN ATTENTE" (POUR VALIDATION)
if ($users["group_name"] === "Conseil") { if ($users["group_name"] === "SuperAdmin") {
return $this->where('demande_status', 'En attente') return $this->where('demande_status', 'En attente')
->orderBy('date_demande', 'DESC') ->orderBy('date_demande', 'DESC')
->findAll(); ->findAll();
} }
// Si le rôle est DIRECTION → voir toutes les demandes aussi (pas filtrées par magasin) // ✅ DIRECTION ET DAF VOIENT TOUTES LES DEMANDES (TOUS STATUTS) POUR CONSULTATION
if ($users["group_name"] === "Direction") { if ($users["group_name"] === "Direction" || $users["group_name"] === "DAF") {
return $this->orderBy('date_demande', 'DESC') return $this->orderBy('date_demande', 'DESC')
->findAll(); ->findAll();
} }
// Autres rôles (Caissière, etc.) → voir uniquement celles de son magasin // ✅ AUTRES RÔLES : VOIR UNIQUEMENT CELLES DE LEUR MAGASIN
return $this->where('id_store', $users['store_id']) return $this->where('id_store', $users['store_id'])
->orderBy('date_demande', 'DESC') ->orderBy('date_demande', 'DESC')
->findAll(); ->findAll();
} catch (\Exception $e) { } catch (\Exception $e) {
log_message('error', 'Erreur lors de la récupération des demandes du jour : ' . $e->getMessage()); log_message('error', 'Erreur lors de la récupération des demandes : ' . $e->getMessage());
return []; return [];
} }
} }
@ -61,11 +57,6 @@ class Remise extends Model
->first(); ->first();
} }
/**
* Récupère l'ID de la commande associée à une demande de remise
* @param int $id_demande
* @return int|null
*/
public function getOrderIdByDemandeId(int $id_demande): ?int public function getOrderIdByDemandeId(int $id_demande): ?int
{ {
$result = $this->select('id_order') $result = $this->select('id_order')
@ -83,10 +74,7 @@ class Remise extends Model
} }
try { try {
// Mettre à jour uniquement les données de la demande de remise
// On ne touche PAS aux montants de la commande ici
$updateResult = $this->update($id, $data); $updateResult = $this->update($id, $data);
return $updateResult; return $updateResult;
} catch (\Exception $e) { } catch (\Exception $e) {
@ -109,11 +97,9 @@ class Remise extends Model
$existing = $this->where('id_order', $id)->first(); $existing = $this->where('id_order', $id)->first();
if ($existing) { if ($existing) {
// Mise à jour
$this->update($existing['id_demande'], $data); $this->update($existing['id_demande'], $data);
return "Remise mise à jour avec succès."; return "Remise mise à jour avec succès.";
} else { } else {
// Création
$this->insert($data); $this->insert($data);
return "Nouvelle remise créée avec succès."; return "Nouvelle remise créée avec succès.";
} }

2
app/Models/Securite.php

@ -35,7 +35,7 @@ class Securite extends Model
{ {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
if ($users["group_name"] == "Direction") { if ($users["group_name"] == "Direction" || $users["group_name"] == "SuperAdmin" || $users["group_name"] == "DAF") {
return $this->where('active', true) return $this->where('active', true)
->findAll(); ->findAll();
} }

123
app/Models/SortieCaisse.php

@ -5,16 +5,10 @@ use CodeIgniter\Model;
class SortieCaisse extends Model class SortieCaisse extends Model
{ {
/**
* table name
* @var string
*/
protected $table = 'sortie_caisse'; protected $table = 'sortie_caisse';
protected $primaryKey = 'id_sortie'; // Primary key column protected $primaryKey = 'id_sortie';
// Dans le fichier App/Models/SortieCaisse.php
// Mettre à jour le tableau $allowedFields
protected $allowedFields = [ protected $allowedFields = [
'montant_retire', 'montant_retire',
'date_retrait', 'date_retrait',
'motif', 'motif',
@ -33,16 +27,13 @@ protected $allowedFields = [
'store_id', 'store_id',
'mime_type', 'mime_type',
'admin_raison', 'admin_raison',
// Champs pour le formulaire IM1
'nom_demandeur', 'nom_demandeur',
'fonction_demandeur', 'fonction_demandeur',
'mode_paiement', 'mode_paiement',
'montant_lettre', 'montant_lettre',
'date_demande', 'date_demande',
'reference', 'reference',
// ✅ NOUVEAU CHAMP 'date_paiement_effectif',
'date_paiement_effectif', // Date à laquelle la caissière a effectué le paiement
// Champs pour le formulaire IM2/IM3
'numero_fiche', 'numero_fiche',
'date_fiche', 'date_fiche',
'service_demandeur', 'service_demandeur',
@ -61,41 +52,28 @@ protected $allowedFields = [
'visa_conseil', 'visa_conseil',
'date_visa_conseil', 'date_visa_conseil',
'observations' 'observations'
]; ];
public function getAllSortieCaisse()
{ /**
* ✅ MODIFICATION : DAF, Direction, SuperAdmin voient TOUS les stores
* Caissière voit uniquement SES décaissements
*/
public function getAllSortieCaisse()
{
try { try {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
// ✅ DIRECTION : Voir uniquement les décaissements de SON store // ✅ DAF, Direction, SuperAdmin : Voir TOUS les stores
if ($users['group_name'] === 'Direction') { if (in_array($users['group_name'], ['Direction', 'DAF', 'SuperAdmin'])) {
return $this
->select('*')
->where('store_id', $users['store_id']) // ✅ FILTRE PAR STORE
->orderBy('date_retrait', 'DESC')
->findAll();
}
// ✅ DAF : Voir uniquement les décaissements de SON store
if ($users['group_name'] === 'DAF') {
return $this return $this
->select('*') ->select('*')
->where('store_id', $users['store_id']) // ✅ FILTRE PAR STORE
->orderBy('date_retrait', 'DESC') ->orderBy('date_retrait', 'DESC')
->findAll(); ->findAll();
} }
// ✅ CONSEIL : Voir TOUS les décaissements (multi-stores)
// if ($users['group_name'] === 'Conseil') {
// return $this
// ->select('*')
// ->orderBy('date_retrait', 'DESC')
// ->findAll();
// }
// ✅ CAISSIÈRE : Voir uniquement SES décaissements // ✅ CAISSIÈRE : Voir uniquement SES décaissements
if($users["group_name"]==="Caissière"){ if($users["group_name"] === "Caissière"){
return $this return $this
->select('*') ->select('*')
->where('user_id', $users['id']) ->where('user_id', $users['id'])
@ -113,48 +91,29 @@ public function getAllSortieCaisse()
log_message('error', 'Erreur lors de la récupération des sorties caisse : ' . $e->getMessage()); log_message('error', 'Erreur lors de la récupération des sorties caisse : ' . $e->getMessage());
return []; return [];
} }
} }
public function getAllSortieCaisse1() /**
{ * ✅ MODIFICATION : Même logique pour les décaissements filtrés
*/
public function getAllSortieCaisse1()
{
try { try {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
// ✅ DIRECTION : Voir uniquement les décaissements de SON store // ✅ DAF, Direction, SuperAdmin : Voir TOUS les stores
if ($users['group_name'] === 'Direction') { if (in_array($users['group_name'], ['Direction', 'DAF', 'SuperAdmin'])) {
return $this
->select('*')
->join('user_group', 'user_group.user_id = sortie_caisse.user_id')
->where('user_group.group_id', 7)
->where('sortie_caisse.store_id', $users['store_id']) // ✅ FILTRE PAR STORE
->orderBy('date_retrait', 'DESC')
->findAll();
}
// ✅ DAF : Voir uniquement les décaissements de SON store
if ($users['group_name'] === 'DAF') {
return $this return $this
->select('*') ->select('*')
->join('user_group', 'user_group.user_id = sortie_caisse.user_id') ->join('user_group', 'user_group.user_id = sortie_caisse.user_id')
->where('user_group.group_id', 7) ->where('user_group.group_id', 7)
->where('sortie_caisse.store_id', $users['store_id']) // ✅ FILTRE PAR STORE
->orderBy('date_retrait', 'DESC') ->orderBy('date_retrait', 'DESC')
->findAll(); ->findAll();
} }
// ✅ CONSEIL : Voir TOUS les stores
// if ($users['group_name'] === 'Conseil') {
// return $this
// ->select('*')
// ->join('user_group', 'user_group.user_id = sortie_caisse.user_id')
// ->where('user_group.group_id', 6)
// ->orderBy('date_retrait', 'DESC')
// ->findAll();
// }
// ✅ CAISSIÈRE : Voir uniquement SES décaissements // ✅ CAISSIÈRE : Voir uniquement SES décaissements
if($users["group_name"]==="Caissière"){ if($users["group_name"] === "Caissière"){
return $this return $this
->select('*') ->select('*')
->where('user_id', $users['id']) ->where('user_id', $users['id'])
@ -171,7 +130,8 @@ public function getAllSortieCaisse1()
log_message('error', 'Erreur lors de la récupération des sorties caisse : ' . $e->getMessage()); log_message('error', 'Erreur lors de la récupération des sorties caisse : ' . $e->getMessage());
return []; return [];
} }
} }
public function addSortieCaisse(array $data) { public function addSortieCaisse(array $data) {
try { try {
return $this->insert($data); return $this->insert($data);
@ -203,15 +163,15 @@ public function getAllSortieCaisse1()
return $reparation; return $reparation;
} }
/**
* ✅ MODIFICATION : DAF, Direction, SuperAdmin voient TOUS les totaux
*/
public function getTotalSortieCaisse() { public function getTotalSortieCaisse() {
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
// ✅ DIRECTION et DAF : Voir uniquement leur store // ✅ DAF, Direction, SuperAdmin : Voir TOUS les stores
$isAdmin = in_array($users['group_name'], ['Direction', 'DAF']); $isAdmin = in_array($users['group_name'], ['Direction', 'DAF', 'SuperAdmin']);
// ✅ CONSEIL : Voir TOUS les stores
$isConseil = $users['group_name'] === 'Conseil';
if ($isAdmin) { if ($isAdmin) {
try { try {
@ -221,7 +181,7 @@ public function getAllSortieCaisse1()
SUM(CASE WHEN mode_paiement = "Virement Bancaire" THEN montant_retire ELSE 0 END) AS total_virement, SUM(CASE WHEN mode_paiement = "Virement Bancaire" THEN montant_retire ELSE 0 END) AS total_virement,
SUM(montant_retire) AS mr SUM(montant_retire) AS mr
') ')
->where('store_id', $users['store_id']) // ✅ FILTRE PAR STORE // ✅ SUPPRESSION DU FILTRE PAR STORE
->whereIn('statut', ['Valider', 'Payé']) ->whereIn('statut', ['Valider', 'Payé'])
->get() ->get()
->getRowObject(); ->getRowObject();
@ -234,27 +194,6 @@ public function getAllSortieCaisse1()
'mr' => 0 'mr' => 0
]; ];
} }
} elseif ($isConseil) {
// ✅ CONSEIL voit TOUS les stores
try {
return $this->select('
SUM(CASE WHEN mode_paiement = "En espèce" THEN montant_retire ELSE 0 END) AS total_espece,
SUM(CASE WHEN mode_paiement = "MVOLA" THEN montant_retire ELSE 0 END) AS total_mvola,
SUM(CASE WHEN mode_paiement = "Virement Bancaire" THEN montant_retire ELSE 0 END) AS total_virement,
SUM(montant_retire) AS mr
')
->whereIn('statut', ['Valider', 'Payé'])
->get()
->getRowObject();
} catch (\Exception $e) {
log_message('error', 'Erreur getTotalSortieCaisse (Conseil) : ' . $e->getMessage());
return (object)[
'total_espece' => 0,
'total_mvola' => 0,
'total_virement' => 0,
'mr' => 0
];
}
} else { } else {
// ✅ CAISSIÈRE : Uniquement son store // ✅ CAISSIÈRE : Uniquement son store
try { try {

8
app/Views/avances/avance.php

@ -44,13 +44,13 @@
<?php <?php
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = isset($users['group_name']) && in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = isset($users['group_name']) && in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
$isCommerciale = isset($users['group_name']) && in_array($users['group_name'], ['COMMERCIALE']); $isCommerciale = isset($users['group_name']) && in_array($users['group_name'], ['COMMERCIALE']);
$isCaissier = isset($users['group_name']) && in_array($users['group_name'], ['Caissière']); $isCaissier = isset($users['group_name']) && in_array($users['group_name'], ['Caissière']);
?> ?>
<!-- Bouton de vérification des avances expirées --> <!-- Bouton de vérification des avances expirées -->
<?php if (isset($users['group_name']) && in_array($users['group_name'], ['Conseil', 'Direction', 'DAF'])): ?> <?php if (isset($users['group_name']) && in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF'])): ?>
<div class="row mb-3"> <div class="row mb-3">
<div class="col-md-12 text-right"> <div class="col-md-12 text-right">
<button <button
@ -70,7 +70,7 @@ $isCaissier = isset($users['group_name']) && in_array($users['group_name'], ['Ca
<thead> <thead>
<?php $session = session(); <?php $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction','DAF']);
$isCommerciale = in_array($users['group_name'], ['COMMERCIALE']); $isCommerciale = in_array($users['group_name'], ['COMMERCIALE']);
$isCaissier = in_array($users['group_name'], ['Caissière']); $isCaissier = in_array($users['group_name'], ['Caissière']);
if ($isAdmin): ?> if ($isAdmin): ?>
@ -90,7 +90,7 @@ $isCaissier = isset($users['group_name']) && in_array($users['group_name'], ['Ca
<?php endif;?> <?php endif;?>
<?php $session = session(); <?php $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Conseil', 'Direction']); $isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
$isCommerciale = in_array($users['group_name'], ['COMMERCIALE']); $isCommerciale = in_array($users['group_name'], ['COMMERCIALE']);
$isCaissier = in_array($users['group_name'], ['Caissière']); $isCaissier = in_array($users['group_name'], ['Caissière']);
if ($isCommerciale || $isCaissier): ?> if ($isCommerciale || $isCaissier): ?>

2
app/Views/dashboard.php

@ -325,7 +325,7 @@
</div> </div>
<?php $session = session(); <?php $session = session();
$users = $session->get('user'); $users = $session->get('user');
if ($users["group_name"] === "Direction") : if ($users["group_name"] === "Direction" || $users["group_name"] === "SuperAdmin" || $users["group_name"] === "DAF" ) :
?> ?>
<div class="col-md-3"> <div class="col-md-3">

135
app/Views/login.php

@ -12,7 +12,7 @@
<link rel="stylesheet" href="<?php echo base_url('assets/dist/css/AdminLTE.min.css') ?>"> <link rel="stylesheet" href="<?php echo base_url('assets/dist/css/AdminLTE.min.css') ?>">
<!-- Google Font --> <!-- Google Font -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap" rel="stylesheet">
<style> <style>
body { body {
@ -22,6 +22,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
overflow: hidden;
} }
.login-card { .login-card {
@ -39,10 +40,6 @@
.login-image { .login-image {
flex: 1; flex: 1;
background: url('https://lh3.googleusercontent.com/p/AF1QipN4iewRbD9iIfbsvyPTD2SGUkxyi952uG30pHD9=s1360-w1360-h1020') center/cover no-repeat; background: url('https://lh3.googleusercontent.com/p/AF1QipN4iewRbD9iIfbsvyPTD2SGUkxyi952uG30pHD9=s1360-w1360-h1020') center/cover no-repeat;
/* Alternative possible :
https://images.unsplash.com/photo-1520975661595-6453be3f7070?auto=format&fit=crop&w=1000&q=80
(casque de moto)
*/
position: relative; position: relative;
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -138,6 +135,96 @@
to { opacity: 1; transform: translateY(0); } to { opacity: 1; transform: translateY(0); }
} }
/* Animation de chargement */
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #007bff, #0056b3);
display: none;
justify-content: center;
align-items: center;
z-index: 9999;
animation: overlayFadeIn 0.5s ease;
}
.loading-overlay.active {
display: flex;
}
.loading-content {
text-align: center;
color: white;
}
.loading-logo {
font-size: 3.5em;
font-weight: 700;
color: #ffcc00;
margin-bottom: 30px;
animation: logoReveal 1.2s ease-in-out;
letter-spacing: 3px;
}
.motorcycle-icon {
font-size: 4em;
margin-bottom: 20px;
animation: bikeRide 1.5s ease-in-out infinite;
}
.loading-text {
font-size: 1.2em;
margin-top: 20px;
opacity: 0;
animation: textFadeIn 0.8s ease 0.5s forwards;
}
.loading-spinner {
width: 60px;
height: 60px;
border: 4px solid rgba(255, 255, 255, 0.3);
border-top: 4px solid #ffcc00;
border-radius: 50%;
margin: 30px auto;
animation: spin 1s linear infinite;
}
@keyframes overlayFadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes logoReveal {
0% {
opacity: 0;
transform: scale(0.5) rotateY(-90deg);
}
50% {
transform: scale(1.1) rotateY(0deg);
}
100% {
opacity: 1;
transform: scale(1) rotateY(0deg);
}
}
@keyframes bikeRide {
0%, 100% { transform: translateX(-20px) rotate(-2deg); }
50% { transform: translateX(20px) rotate(2deg); }
}
@keyframes textFadeIn {
to {
opacity: 1;
}
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@media (max-width: 768px) { @media (max-width: 768px) {
.login-card { .login-card {
flex-direction: column; flex-direction: column;
@ -149,11 +236,27 @@
.login-form { .login-form {
padding: 25px; padding: 25px;
} }
.loading-logo {
font-size: 2.5em;
}
.motorcycle-icon {
font-size: 3em;
}
} }
</style> </style>
</head> </head>
<body> <body>
<!-- Overlay de chargement -->
<div class="loading-overlay" id="loadingOverlay">
<div class="loading-content">
<div class="motorcycle-icon">🏍️</div>
<div class="loading-logo">MOTORBIKE</div>
<div class="loading-spinner"></div>
<div class="loading-text">Démarrage en cours...</div>
</div>
</div>
<div class="login-card"> <div class="login-card">
<!-- Image + message --> <!-- Image + message -->
@ -174,7 +277,7 @@
</div> </div>
<?php endif; ?> <?php endif; ?>
<form action="<?= base_url('login') ?>" method="post"> <form action="<?= base_url('login') ?>" method="post" id="loginForm">
<div class="input-group"> <div class="input-group">
<span class="input-group-addon"><i class="fa fa-envelope"></i></span> <span class="input-group-addon"><i class="fa fa-envelope"></i></span>
<input type="email" class="form-control" name="email" placeholder="Email" required> <input type="email" class="form-control" name="email" placeholder="Email" required>
@ -197,5 +300,25 @@
<script src="<?php echo base_url('assets/bower_components/jquery/dist/jquery.min.js') ?>"></script> <script src="<?php echo base_url('assets/bower_components/jquery/dist/jquery.min.js') ?>"></script>
<script src="<?php echo base_url('assets/bower_components/bootstrap/dist/js/bootstrap.min.js') ?>"></script> <script src="<?php echo base_url('assets/bower_components/bootstrap/dist/js/bootstrap.min.js') ?>"></script>
<script>
document.getElementById('loginForm').addEventListener('submit', function(e) {
// Afficher l'animation de chargement
document.getElementById('loadingOverlay').classList.add('active');
// Le formulaire se soumettra normalement
// L'animation reste visible pendant le traitement côté serveur
});
// Si vous voulez tester l'animation en local sans backend
// décommentez cette fonction et appelez testAnimation()
function testAnimation() {
document.getElementById('loadingOverlay').classList.add('active');
setTimeout(function() {
alert('Animation terminée ! En production, vous seriez redirigé vers le dashboard.');
document.getElementById('loadingOverlay').classList.remove('active');
}, 2500);
}
</script>
</body> </body>
</html> </html>

4
app/Views/orders/avance.php

@ -26,7 +26,7 @@
<thead> <thead>
<?php $session = session(); <?php $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Direction', 'Conseil']); $isAdmin = in_array($users['group_name'], ['Direction', 'SuperAdmin']);
$isCommerciale = in_array($users['group_name'], ['COMMERCIALE']); $isCommerciale = in_array($users['group_name'], ['COMMERCIALE']);
$isCaissier = in_array($users['group_name'], ['Caissier']); $isCaissier = in_array($users['group_name'], ['Caissier']);
if ($isAdmin): ?> if ($isAdmin): ?>
@ -46,7 +46,7 @@
<?php endif;?> <?php endif;?>
<?php $session = session(); <?php $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = in_array($users['group_name'], ['Direction', 'Conseil']); $isAdmin = in_array($users['group_name'], ['Direction', 'SuperAdmin']);
$isCommerciale = in_array($users['group_name'], ['COMMERCIALE']); $isCommerciale = in_array($users['group_name'], ['COMMERCIALE']);
$isCaissier = in_array($users['group_name'], ['Caissier']); $isCaissier = in_array($users['group_name'], ['Caissier']);
if ($isCommerciale || $isCaissier): ?> if ($isCommerciale || $isCaissier): ?>

2
app/Views/orders/edit.php

@ -306,7 +306,7 @@
<label for="paid_status" class="col-sm-5 control-label">Statut payant</label> <label for="paid_status" class="col-sm-5 control-label">Statut payant</label>
<div class="col-sm-7"> <div class="col-sm-7">
<select type="text" class="form-control" id="paid_status" name="paid_status"> <select type="text" class="form-control" id="paid_status" name="paid_status">
<option value="1">Validé</option> <option value="1">Payé</option>
<option value="2">Refusé</option> <option value="2">Refusé</option>
</select> </select>
</div> </div>

84
app/Views/orders/index.php

@ -50,7 +50,7 @@
<?php <?php
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
if ($users['group_name'] === 'Conseil' || $users['group_name'] === "Direction") { if ($users['group_name'] === 'SuperAdmin' || $users['group_name'] === "Direction" || $users['group_name'] === "DAF" ) {
?> ?>
<th>Facture n°</th> <th>Facture n°</th>
<th>Nom du client</th> <th>Nom du client</th>
@ -58,7 +58,7 @@
<th>Date et Heure</th> <th>Date et Heure</th>
<th>Prix demandé</th> <th>Prix demandé</th>
<th>Prix de vente</th> <th>Prix de vente</th>
<th>Validation</th> <th>Status</th>
<?php if ( <?php if (
in_array('updateOrder', $user_permission) in_array('updateOrder', $user_permission)
@ -79,7 +79,7 @@
<th>Date et Heure</th> <th>Date et Heure</th>
<th>Prix demandé</th> <th>Prix demandé</th>
<th>Prix de vente</th> <th>Prix de vente</th>
<th>Validation</th> <th>Status</th>
<?php if ( <?php if (
in_array('viewOrder', $user_permission) in_array('viewOrder', $user_permission)
|| in_array('updateOrder', $user_permission) || in_array('updateOrder', $user_permission)
@ -135,6 +135,7 @@
<?php endif; ?> <?php endif; ?>
<!-- Modal -->
<!-- Modal --> <!-- Modal -->
<div class="modal fade" id="viewOrderModal" tabindex="-1" role="dialog" aria-labelledby="viewOrderModalLabel"> <div class="modal fade" id="viewOrderModal" tabindex="-1" role="dialog" aria-labelledby="viewOrderModalLabel">
<div class="modal-dialog modal-lg" role="document"> <div class="modal-dialog modal-lg" role="document">
@ -181,20 +182,22 @@
</div> </div>
</div> </div>
<!-- Tableau produits --> <!-- Tableau produits avec toutes les infos sur une ligne -->
<h4>Produits</h4> <h4>Informations de la commande</h4>
<table class="table table-bordered table-striped" id="view_products_table"> <table class="table table-bordered table-striped" id="view_products_table">
<thead> <thead>
<tr><th>Marque</th><th>Designation</th><th>Numéro de Série</th><th>Prix Unitaire</th></tr> <tr>
<th>Marque</th>
<th>Désignation</th>
<th>Numéro de Série</th>
<th>N° de Moteur</th>
<th>Châssis</th>
<th>N° Facture</th>
<th>Statut</th>
</tr>
</thead> </thead>
<tbody></tbody> <tbody></tbody>
</table> </table>
<!-- Totaux -->
<table class="table table-bordered table-striped" id="view_totals">
<tr><th>Montant brut</th><th>Rabais</th><th>Statut</th></tr>
<tr><td id="gross_amount"></td><td id="discount"></td><td id="paid_status"></td></tr>
</table>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
@ -284,8 +287,10 @@
'</div>' '</div>'
); );
// Mettre à jour le statut dans la modal // Mettre à jour le statut dans toutes les lignes du tableau
$('#paid_status').html('<span class="label label-info">Validé et Livré</span>'); $('#view_products_table tbody tr').each(function() {
$(this).find('td:last').html('<span class="label label-info">Payé et Livré</span>');
});
// Cacher le bouton "Livré" // Cacher le bouton "Livré"
$('#btn-mark-delivered').hide(); $('#btn-mark-delivered').hide();
@ -364,6 +369,7 @@
} }
} }
// ✅ FONCTION MODIFIÉE POUR AFFICHER LES NOUVELLES COLONNES
$(document).on('click', '.btn-view', function(e) { $(document).on('click', '.btn-view', function(e) {
e.preventDefault(); e.preventDefault();
var orderId = $(this).data('order-id'); var orderId = $(this).data('order-id');
@ -384,7 +390,25 @@
$('#customer_phone').text(d.customer_phone); $('#customer_phone').text(d.customer_phone);
$('#customer_cin').text(d.customer_cin); $('#customer_cin').text(d.customer_cin);
// Produits // Déterminer le statut une seule fois
var statutHtml = '';
if (d.paid_status == 1) {
statutHtml = '<span class="label label-success">Payé</span>';
<?php if ($users['group_name'] === 'SECURITE'): ?>
$('#btn-mark-delivered').show();
<?php endif; ?>
} else if (d.paid_status == 2) {
statutHtml = '<span class="label label-warning">En Attente</span>';
$('#btn-mark-delivered').hide();
} else if (d.paid_status == 3) {
statutHtml = '<span class="label label-info">Payé et Livré</span>';
$('#btn-mark-delivered').hide();
} else {
statutHtml = '<span class="label label-danger">Refusé</span>';
$('#btn-mark-delivered').hide();
}
// Produits avec les nouvelles colonnes
var $tb = $('#view_products_table tbody'); var $tb = $('#view_products_table tbody');
$tb.empty(); $tb.empty();
$.each(response.order_data.order_item, function(_, item) { $.each(response.order_data.order_item, function(_, item) {
@ -405,41 +429,21 @@
} }
}); });
// ✅ AJOUT DES NOUVELLES COLONNES : N° Moteur, Châssis, N° Facture, Statut
$tb.append( $tb.append(
'<tr>' + '<tr>' +
'<td>' + (brandName || 'Aucune marque') + '</td>' + '<td>' + (brandName || 'Aucune marque') + '</td>' +
'<td>' + (product.name || '') + '</td>' + '<td>' + (product.name || '') + '</td>' +
'<td>' + (product.sku || '') + '</td>' + '<td>' + (product.sku || '') + '</td>' +
'<td>' + parseInt(item.amount).toLocaleString('fr-MG', { minimumFractionDigits: 0, maximumFractionDigits: 0 }) + ' Ar</td>' + '<td>' + (product.numero_de_moteur || 'N/A') + '</td>' +
'<td>' + (product.chasis || 'N/A') + '</td>' +
'<td>' + (d.bill_no || 'N/A') + '</td>' +
'<td>' + statutHtml + '</td>' +
'</tr>' '</tr>'
); );
} }
}); });
// Totaux
$('#gross_amount').text(parseInt(d.gross_amount).toLocaleString('fr-MG', { minimumFractionDigits: 0, maximumFractionDigits: 0 }) + ' Ar');
$('#discount').text(parseInt(d.discount).toLocaleString('fr-MG', { minimumFractionDigits: 0, maximumFractionDigits: 0 }) + ' Ar');
// Statut de paiement avec gestion du statut "Livré"
var statutHtml = '';
if (d.paid_status == 1) {
statutHtml = '<span class="label label-success">Validé</span>';
// Afficher le bouton "Livré" pour la sécurité si statut = Validé
<?php if ($users['group_name'] === 'SECURITE'): ?>
$('#btn-mark-delivered').show();
<?php endif; ?>
} else if (d.paid_status == 2) {
statutHtml = '<span class="label label-warning">En Attente</span>';
$('#btn-mark-delivered').hide();
} else if (d.paid_status == 3) {
statutHtml = '<span class="label label-info">Validé et Livré</span>';
$('#btn-mark-delivered').hide();
} else {
statutHtml = '<span class="label label-danger">Refusé</span>';
$('#btn-mark-delivered').hide();
}
$('#paid_status').html(statutHtml);
// Afficher la modal // Afficher la modal
$('#viewOrderModal').modal('show'); $('#viewOrderModal').modal('show');
}); });

144
app/Views/reports/index.php

@ -303,4 +303,146 @@
} }
} }
}); });
</script> --> </script>
<style>
/* --- Style global --- */
body {
background: #f4f6f9;
font-family: 'Poppins', sans-serif;
}
h1, h3 {
font-weight: 600;
color: #2c3e50;
}
/* --- En-tête --- */
.content-header {
background: linear-gradient(135deg, #3498db, #2ecc71);
color: white;
padding: 25px;
border-radius: 10px;
margin-bottom: 30px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.content-header h1 {
margin: 0;
font-size: 26px;
}
.breadcrumb {
background: transparent;
margin-top: 10px;
}
.breadcrumb li a {
color: #ecf0f1;
}
/* --- Formulaire --- */
.form-inline {
margin-bottom: 25px;
}
.form-inline .form-control,
.form-inline button,
.form-inline a {
border-radius: 8px !important;
}
.btn-default {
background-color: #2980b9;
color: white;
transition: all 0.3s ease;
}
.btn-default:hover {
background-color: #1f618d;
color: white;
}
.btn-success {
transition: all 0.3s ease;
}
.btn-success:hover {
background-color: #27ae60;
}
/* --- Boîtes de statistiques --- */
.box {
background: white;
border-radius: 15px;
box-shadow: 0 6px 15px rgba(0,0,0,0.08);
transition: transform 0.3s ease, box-shadow 0.3s ease;
margin-bottom: 25px;
}
.box:hover {
transform: translateY(-5px);
box-shadow: 0 12px 25px rgba(0,0,0,0.15);
}
.box-header {
border-bottom: 2px solid #f1f1f1;
padding: 15px 20px;
background: #fafafa;
border-radius: 15px 15px 0 0;
}
.box-title {
font-size: 18px;
color: #34495e;
}
.box-body {
padding: 20px;
}
/* --- Table --- */
table {
background: white;
border-radius: 12px;
overflow: hidden;
}
th {
background: #3498db;
color: white;
text-align: center;
}
td {
text-align: center;
vertical-align: middle !important;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
/* --- Alertes --- */
.alert {
border-radius: 10px;
animation: fadeIn 0.6s ease;
}
@keyframes fadeIn {
from {opacity: 0; transform: translateY(-10px);}
to {opacity: 1; transform: translateY(0);}
}
/* --- Charts --- */
canvas {
width: 100% !important;
height: 300px !important;
}
/* --- Responsive --- */
@media (max-width: 768px) {
.box {
margin-bottom: 20px;
}
}
</style>

16
app/Views/sortieCaisse/index.php

@ -125,7 +125,7 @@ input[readonly], select[disabled], textarea[readonly] {
<br> <br>
<?php $session = session(); <?php $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "Conseil"; $isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "SuperAdmin" || $users['group_name'] == "DAF";
$isCaissier = $users['group_name'] == "Caissière"; $isCaissier = $users['group_name'] == "Caissière";
if($isAdmin): ?> if($isAdmin): ?>
<button id="validate_filtered" class="btn btn-primary w-100">A valider</button> <button id="validate_filtered" class="btn btn-primary w-100">A valider</button>
@ -159,7 +159,7 @@ input[readonly], select[disabled], textarea[readonly] {
<th>Action</th> <th>Action</th>
<?php } ?> <?php } ?>
<?php <?php
} elseif ($users['group_name'] === 'Direction' || $users['group_name'] === 'DAF') { } elseif ($users['group_name'] === 'Direction' || $users['group_name'] === 'DAF' || $users['group_name'] === 'SuperAdmin') {
?> ?>
<th>#</th> <th>#</th>
<th>Montant</th> <th>Montant</th>
@ -296,7 +296,7 @@ input[readonly], select[disabled], textarea[readonly] {
<?php <?php
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "Conseil"; $isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "SuperAdmin" || $users['group_name'] == "DAF";
$isCaissier = $users['group_name'] == "Caissière"; $isCaissier = $users['group_name'] == "Caissière";
$options = $isAdmin ? $admin_options : $caissier_options; $options = $isAdmin ? $admin_options : $caissier_options;
@ -522,9 +522,9 @@ input[readonly], select[disabled], textarea[readonly] {
<td><input type="date" class="form-control" name="date_visa_direction"></td> <td><input type="date" class="form-control" name="date_visa_direction"></td>
</tr> </tr>
<tr> <tr>
<td>Conseil d'Administration</td> <td>SuperAdmin</td>
<td><input type="text" class="form-control" name="visa_conseil" placeholder="Nom et signature"></td> <td><input type="text" class="form-control" name="visa_superAdmin" placeholder="Nom et signature"></td>
<td><input type="date" class="form-control" name="date_visa_conseil"></td> <td><input type="date" class="form-control" name="date_superAdmin"></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -605,7 +605,7 @@ input[readonly], select[disabled], textarea[readonly] {
<?php <?php
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "Conseil"; $isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "SuperAdmin" || $users['group_name'] == "DAF";
$options = $isAdmin ? $admin_options : $caissier_options; $options = $isAdmin ? $admin_options : $caissier_options;
echo "<option value=''>Veuillez sélectionner une raison</option>\n"; echo "<option value=''>Veuillez sélectionner une raison</option>\n";
@ -1038,7 +1038,7 @@ $(document).ready(function() {
<?php <?php
$session = session(); $session = session();
$users = $session->get('user'); $users = $session->get('user');
$isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "Conseil"; $isAdmin = $users['group_name'] == "Direction" || $users['group_name'] == "SuperAdmin" || $users['group_name'] == "DAF";
?> ?>
<?php if($isAdmin): ?> <?php if($isAdmin): ?>

163
app/Views/statistic/index.php

@ -1,5 +1,140 @@
<style>
/* --- Style général --- */
body {
background: #f4f6f9;
font-family: 'Poppins', sans-serif;
}
h1 {
font-weight: 600;
color: #2c3e50;
}
small {
color: #7f8c8d;
}
/* --- En-tête --- */
.content-header {
background: linear-gradient(135deg, #3498db, #2ecc71);
color: white;
padding: 25px;
border-radius: 12px;
margin-bottom: 25px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.breadcrumb {
background: transparent;
margin-top: 10px;
}
.breadcrumb a {
color: #ecf0f1;
}
/* --- Boîte principale --- */
.box {
background: white;
border-radius: 16px;
box-shadow: 0 6px 15px rgba(0,0,0,0.08);
padding: 20px;
animation: fadeIn 0.6s ease;
}
@keyframes fadeIn {
from {opacity: 0; transform: translateY(15px);}
to {opacity: 1; transform: translateY(0);}
}
/* --- Cartes utilisateurs --- */
.small-box {
position: relative;
background: linear-gradient(135deg, #3498db, #2980b9);
color: white;
border-radius: 15px;
box-shadow: 0 8px 18px rgba(0,0,0,0.15);
transition: transform 0.3s ease, box-shadow 0.3s ease;
overflow: hidden;
}
.small-box:hover {
transform: translateY(-6px);
box-shadow: 0 12px 24px rgba(0,0,0,0.25);
}
.small-box .inner {
padding: 20px;
text-align: center;
}
.small-box h3 {
font-size: 22px;
margin-bottom: 10px;
font-weight: 600;
text-transform: capitalize;
}
.small-box p {
font-size: 15px;
}
.small-box b {
color: #f1c40f;
}
.small-box .icon {
position: absolute;
top: 10px;
right: 15px;
font-size: 60px;
opacity: 0.15;
transition: opacity 0.3s ease;
}
.small-box:hover .icon {
opacity: 0.3;
}
.small-box-footer {
display: block;
text-align: center;
padding: 10px;
color: #ecf0f1;
background: rgba(0,0,0,0.15);
border-radius: 0 0 15px 15px;
text-decoration: none;
font-weight: 500;
transition: background 0.3s ease;
}
.small-box-footer:hover {
background: rgba(0,0,0,0.3);
}
/* --- Couleurs aléatoires dynamiques pour chaque carte --- */
.small-box:nth-child(4n+1) {
background: linear-gradient(135deg, #3498db, #2980b9);
}
.small-box:nth-child(4n+2) {
background: linear-gradient(135deg, #2ecc71, #27ae60);
}
.small-box:nth-child(4n+3) {
background: linear-gradient(135deg, #e67e22, #d35400);
}
.small-box:nth-child(4n+4) {
background: linear-gradient(135deg, #9b59b6, #8e44ad);
}
/* --- Responsive --- */
@media (max-width: 768px) {
.small-box {
margin-bottom: 15px;
}
}
</style>
<div class="content-wrapper"> <div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header"> <section class="content-header">
<h1> <h1>
Tableau de bord Tableau de bord
@ -12,50 +147,44 @@
</section> </section>
<section class="content"> <section class="content">
<div class="box" style="padding-top: 5px; padding-left: 5px; padding-right: 5px"> <div class="box">
<?php if ($is_admin == true): ?> <?php if ($is_admin == true): ?>
<div class="row" id="dataToMap"></div> <div class="row" id="dataToMap"></div>
<!-- /.row -->
<?php endif; ?> <?php endif; ?>
</div> </div>
</section> </section>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function() { $(document).ready(function() {
$("#dashboardMainMenu").addClass('active'); $("#dashboardMainMenu").addClass('active');
}); });
// Convert PHP array to JavaScript array
const allUsers = <?php echo json_encode($allUsers); ?>; const allUsers = <?php echo json_encode($allUsers); ?>;
console.log(allUsers);
// Function to render users
function renderUsers(users) { function renderUsers(users) {
const container = document.getElementById('dataToMap'); const container = document.getElementById('dataToMap');
container.innerHTML = ''; // Clear existing content container.innerHTML = '';
users.forEach(user => { users.forEach(user => {
const userHtml = ` const userHtml = `
<div class="col-lg-3 col-xs-6"> <div class="col-lg-3 col-md-4 col-sm-6 col-xs-12">
<div class="small-box" style="background-color: rgba(54, 162, 235, 0.5);"> <div class="small-box">
<div class="inner"> <div class="inner">
<h3>${user.username}</h3> <h3>${user.username}</h3>
<p>Produits vendues <b style="font-size: 20px;">${user.totalVente}</b></p> <p>Produits vendus : <b>${user.totalVente}</b></p>
</div> </div>
<div class="icon"> <div class="icon">
<i class="ion ion-stats-bars"></i> <i class="ion ion-stats-bars"></i>
</div> </div>
<a href="<?php echo base_url('statistic/') ?>${user.id}" class="small-box-footer"> <a href="<?php echo base_url('statistic/') ?>${user.id}" class="small-box-footer">
Plus d'information <i class="fa fa-arrow-circle-right"></i> Plus d'informations <i class="fa fa-arrow-circle-right"></i>
</a> </a>
</div> </div>
</div> </div>`;
`; container.innerHTML += userHtml;
container.innerHTML += userHtml; // Append the user HTML to the container
}); });
} }
// Render all users initially
renderUsers(allUsers); renderUsers(allUsers);
</script> </script>

1
app/Views/templates/header.php

@ -909,4 +909,5 @@
} }
</style> </style>
Loading…
Cancel
Save