Compare commits
1 Commits
master
...
feat/notif
| Author | SHA1 | Date | |
|---|---|---|---|
| 421b784b4a |
@ -22,6 +22,7 @@ use App\Controllers\ReservationController;
|
||||
use App\Controllers\SecuriteController;
|
||||
use App\Controllers\SortieCaisseController;
|
||||
use App\Controllers\RemiseController;
|
||||
use App\Controllers\PerformanceController;
|
||||
/**
|
||||
* auth route
|
||||
* the option array filter make a filter,
|
||||
@ -49,7 +50,6 @@ $routes->group('', ['filter' => 'auth'], function ($routes) {
|
||||
* dashboard route
|
||||
*/
|
||||
$routes->get('/', [Dashboard::class, 'index']);
|
||||
$routes->get('/dashboard/getTresorerieData', [Dashboard::class, 'getTresorerieData']);
|
||||
$routes->get('/ventes', [Auth::class, 'ventes']);
|
||||
$routes->get('/ventes/(:num)', [Auth::class, 'addImage']);
|
||||
$routes->get('/ventes/fetchProductVente/(:num)', [Auth::class, 'fetchProductVente']);
|
||||
@ -183,7 +183,7 @@ $routes->group('', ['filter' => 'auth'], function ($routes) {
|
||||
$routes->get('update/(:num)', [ProductCOntroller::class, 'update']);
|
||||
$routes->post('update/(:num)', [ProductCOntroller::class, 'update']);
|
||||
$routes->post('remove', [ProductCOntroller::class, 'remove']);
|
||||
$routes->get('generateqrcode/(:num)', [QrCodeController::class, 'generate']);
|
||||
$routes->get('generateqrcode/(:num)', [QrCodeCOntroller::class, 'generate']);
|
||||
$routes->post('assign_store', [ProductCOntroller::class, 'assign_store']);
|
||||
$routes->post('createByExcel', [ProductCOntroller::class, 'createByExcel']);
|
||||
$routes->post('checkProductAvailability', [ProductCOntroller::class, 'checkProductAvailability']);
|
||||
@ -226,7 +226,7 @@ $routes->group('', ['filter' => 'auth'], function ($routes) {
|
||||
$routes->get('detail/stock', [ReportController::class, 'stockDetail']);
|
||||
|
||||
// Corrections fetct → fetch
|
||||
$routes->get('detail/fetchData/(:num)', [ReportController::class, 'fetchProductSodled/$1']);
|
||||
$routes->get('detail/fetchData/(:num)', [ReportController::class, 'fetchProductSold/$1']);
|
||||
$routes->get('detail/fetchDataStock/(:num)', [ReportController::class, 'fetchProductStock/$1']);
|
||||
$routes->get('detail/fetchDataStock2/(:num)', [ReportController::class, 'fetchProductStock2/$1']);
|
||||
|
||||
@ -389,13 +389,6 @@ $routes->group('avances', function ($routes) {
|
||||
$routes->post('validateAvance', [AvanceController::class, 'validateAvance']);
|
||||
});
|
||||
|
||||
// Historique des actions (SuperAdmin)
|
||||
$routes->group('action-log', ['filter' => 'auth'], static function ($routes) {
|
||||
$routes->get('/', 'ActionLogController::index');
|
||||
$routes->get('fetchData', 'ActionLogController::fetchData');
|
||||
$routes->get('export', 'ActionLogController::export');
|
||||
});
|
||||
|
||||
// historique
|
||||
$routes->group('historique', ['filter' => 'auth'], static function ($routes) {
|
||||
$routes->get('/', 'HistoriqueController::index');
|
||||
|
||||
@ -59,6 +59,4 @@ class View extends BaseView
|
||||
* @var list<class-string<ViewDecoratorInterface>>
|
||||
*/
|
||||
public array $decorators = [];
|
||||
|
||||
public string $appOverridesFolder = APPPATH . 'Views/';
|
||||
}
|
||||
|
||||
@ -1,154 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\Historique;
|
||||
use App\Models\Stores;
|
||||
|
||||
class ActionLogController extends AdminController
|
||||
{
|
||||
private $pageTitle = 'Historique des Actions';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
helper(['form', 'url']);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$session = session();
|
||||
$user = $session->get('user');
|
||||
|
||||
if ($user['group_name'] !== 'SuperAdmin') {
|
||||
return redirect()->to('/');
|
||||
}
|
||||
|
||||
$storesModel = new Stores();
|
||||
|
||||
$data['page_title'] = $this->pageTitle;
|
||||
$data['stores'] = $storesModel->getActiveStore();
|
||||
|
||||
return $this->render_template('action_log/index', $data);
|
||||
}
|
||||
|
||||
public function fetchData()
|
||||
{
|
||||
$session = session();
|
||||
$user = $session->get('user');
|
||||
|
||||
if ($user['group_name'] !== 'SuperAdmin') {
|
||||
return $this->response->setJSON(['data' => []]);
|
||||
}
|
||||
|
||||
$historiqueModel = new Historique();
|
||||
|
||||
$filters = [
|
||||
'action' => $this->request->getGet('action'),
|
||||
'store_name' => $this->request->getGet('store_name'),
|
||||
'product_name' => $this->request->getGet('product'),
|
||||
'sku' => $this->request->getGet('sku'),
|
||||
'date_from' => $this->request->getGet('date_from'),
|
||||
'date_to' => $this->request->getGet('date_to'),
|
||||
];
|
||||
|
||||
$allData = $historiqueModel->getHistoriqueWithFilters($filters);
|
||||
|
||||
$result = ['data' => []];
|
||||
|
||||
foreach ($allData as $row) {
|
||||
$result['data'][] = [
|
||||
date('d/m/Y H:i', strtotime($row['created_at'])),
|
||||
$row['user_name'] ?? '<em>Système</em>',
|
||||
$this->getActionBadge($row['action']),
|
||||
$this->getTableLabel($row['table_name']),
|
||||
$row['description'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
return $this->response->setJSON($result);
|
||||
}
|
||||
|
||||
private function getActionBadge($action)
|
||||
{
|
||||
$badges = [
|
||||
'CREATE' => '<span class="label label-success">Création</span>',
|
||||
'UPDATE' => '<span class="label label-warning">Modification</span>',
|
||||
'DELETE' => '<span class="label label-danger">Suppression</span>',
|
||||
'PAYMENT' => '<span class="label label-primary">Paiement</span>',
|
||||
'VALIDATE' => '<span class="label label-info">Validation</span>',
|
||||
'REFUSE' => '<span class="label label-danger">Refus</span>',
|
||||
'DELIVERY' => '<span class="label label-success">Livraison</span>',
|
||||
'ASSIGN_STORE' => '<span class="label label-info">Assignation</span>',
|
||||
'ENTRER' => '<span class="label label-primary">Entrée</span>',
|
||||
'SORTIE' => '<span class="label label-default">Sortie</span>',
|
||||
'IMPORT' => '<span class="label label-success">Import</span>',
|
||||
'LOGIN' => '<span class="label label-default">Connexion</span>',
|
||||
];
|
||||
|
||||
return $badges[$action] ?? '<span class="label label-secondary">' . $action . '</span>';
|
||||
}
|
||||
|
||||
private function getTableLabel($tableName)
|
||||
{
|
||||
$labels = [
|
||||
'orders' => 'Commande',
|
||||
'products' => 'Produit',
|
||||
'users' => 'Utilisateur',
|
||||
'groups' => 'Rôle',
|
||||
'avances' => 'Avance',
|
||||
'securite' => 'Sécurité',
|
||||
'remise' => 'Remise',
|
||||
'sortie_caisse' => 'Décaissement',
|
||||
'autres_encaissements' => 'Encaissement',
|
||||
'recouvrement' => 'Recouvrement',
|
||||
'stores' => 'Point de vente',
|
||||
'brands' => 'Marque',
|
||||
'categories' => 'Catégorie',
|
||||
];
|
||||
|
||||
return $labels[$tableName] ?? $tableName;
|
||||
}
|
||||
|
||||
public function export()
|
||||
{
|
||||
$session = session();
|
||||
$user = $session->get('user');
|
||||
|
||||
if ($user['group_name'] !== 'SuperAdmin') {
|
||||
return redirect()->to('/');
|
||||
}
|
||||
|
||||
$historiqueModel = new Historique();
|
||||
|
||||
$filters = [
|
||||
'action' => $this->request->getGet('action'),
|
||||
'store_name' => $this->request->getGet('store_name'),
|
||||
'date_from' => $this->request->getGet('date_from'),
|
||||
'date_to' => $this->request->getGet('date_to'),
|
||||
];
|
||||
|
||||
$data = $historiqueModel->getHistoriqueWithFilters($filters);
|
||||
|
||||
$csv = "\xEF\xBB\xBF"; // BOM UTF-8 pour Excel
|
||||
$csv .= "Date;Heure;Utilisateur;Action;Module;Description\n";
|
||||
|
||||
foreach ($data as $row) {
|
||||
$date = date('d-m-Y', strtotime($row['created_at']));
|
||||
$heure = date('H:i', strtotime($row['created_at']));
|
||||
$userName = $row['user_name'] ?? 'Système';
|
||||
$action = $row['action'];
|
||||
$module = $this->getTableLabel($row['table_name']);
|
||||
$description = str_replace('"', '""', $row['description'] ?? '');
|
||||
|
||||
$csv .= "{$date};{$heure};{$userName};{$action};{$module};\"{$description}\"\n";
|
||||
}
|
||||
|
||||
$filename = 'historique_actions_' . date('Y-m-d_H-i') . '.csv';
|
||||
|
||||
return $this->response
|
||||
->setHeader('Content-Type', 'text/csv; charset=utf-8')
|
||||
->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"')
|
||||
->setBody($csv);
|
||||
}
|
||||
}
|
||||
@ -44,13 +44,6 @@ abstract class AdminController extends BaseController
|
||||
protected function render_template($page = null, $data = [])
|
||||
{
|
||||
$data['user_permission'] = $this->permission;
|
||||
// Charger le logo dynamiquement
|
||||
if (!isset($data['company_logo'])) {
|
||||
$companyModel = new Company();
|
||||
$companyData = $companyModel->getCompanyData(1);
|
||||
$data['company_logo'] = $companyData['logo'] ?? 'assets/images/company_logo.jpg';
|
||||
$data['company_name'] = $companyData['company_name'] ?? 'MotorBike';
|
||||
}
|
||||
echo view('templates/header', $data);
|
||||
echo view('templates/header_menu', $data);
|
||||
echo view('templates/side_menubar', $data);
|
||||
@ -58,14 +51,6 @@ abstract class AdminController extends BaseController
|
||||
echo view('templates/footer', $data);
|
||||
}
|
||||
|
||||
// Get company logo path
|
||||
protected function getCompanyLogo()
|
||||
{
|
||||
$model = new Company();
|
||||
$data = $model->getCompanyData(1);
|
||||
return $data['logo'] ?? 'assets/images/company_logo.jpg';
|
||||
}
|
||||
|
||||
// Get company currency using model
|
||||
public function company_currency()
|
||||
{
|
||||
|
||||
@ -6,7 +6,6 @@ use App\Models\ProductImage;
|
||||
use App\Models\Users;
|
||||
use App\Models\Stores;
|
||||
use App\Models\Products;
|
||||
use App\Models\Historique;
|
||||
|
||||
class Auth extends AdminController
|
||||
{
|
||||
@ -80,10 +79,6 @@ public function loginPost()
|
||||
'logged_in' => true
|
||||
]);
|
||||
|
||||
// Log connexion
|
||||
$historique = new Historique();
|
||||
$historique->logAction('users', 'LOGIN', $user['id'], "Connexion de {$user['firstname']} {$user['lastname']} ({$user['group_name']})");
|
||||
|
||||
// Redirect to dashboard
|
||||
return redirect()->to('/');
|
||||
}
|
||||
@ -129,8 +124,7 @@ public function loginPost()
|
||||
$buttons .= " <a href='/ventes/show/" . $value['id'] . "' class='btn btn-default'><i class='fa fa-eye'></i></a>";
|
||||
}
|
||||
|
||||
$productSoldStatus = (int)($value['product_sold'] ?? 0);
|
||||
if (is_array($this->permission) && in_array('createOrder', $this->permission) && $productSoldStatus === 0) {
|
||||
if (is_array($this->permission) && in_array('createOrder', $this->permission)) {
|
||||
$buttons .= ($value['qty'] == 1)
|
||||
? " <a href='/orders/createFromEspace/" . $value['id'] . "' class='btn btn-default'><i class='fa fa-shopping-cart'></i></a>"
|
||||
: " <button class='btn btn-default' title='0 en stock'><i class='fa fa-shopping-cart'></i></button>";
|
||||
@ -140,16 +134,6 @@ public function loginPost()
|
||||
|
||||
$img = '<img src="' . base_url('assets/images/product_image/' . $value['image']) . '" alt="' . $value['image'] . '" class="img-circle" width="50" height="50" />';
|
||||
|
||||
// Statut basé sur product_sold
|
||||
$productSold = (int)($value['product_sold'] ?? 0);
|
||||
if ($productSold === 2) {
|
||||
$statut = '<span class="label label-warning">En attente de livraison</span>';
|
||||
} elseif ($productSold === 1) {
|
||||
$statut = '<span class="label label-default">Livré</span>';
|
||||
} else {
|
||||
$statut = '<span class="label label-success">Disponible</span>';
|
||||
}
|
||||
|
||||
// Populate the result data
|
||||
$result['data'][] = [
|
||||
$img,
|
||||
@ -158,7 +142,6 @@ public function loginPost()
|
||||
number_format($value['prix_vente'], 0, ',', ' '),
|
||||
$value['puissance'] . ' CC',
|
||||
$value['numero_de_moteur'],
|
||||
$statut,
|
||||
$buttons
|
||||
];
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ namespace App\Controllers;
|
||||
use App\Models\AutresEncaissements;
|
||||
use App\Models\Stores;
|
||||
use App\Models\Users;
|
||||
use App\Models\Historique;
|
||||
|
||||
class AutresEncaissementsController extends AdminController
|
||||
{
|
||||
@ -42,7 +41,7 @@ class AutresEncaissementsController extends AdminController
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
if (strtolower($this->request->getMethod()) !== 'post') {
|
||||
if ($this->request->getMethod() !== 'post') {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'messages' => 'Méthode non autorisée'
|
||||
@ -104,13 +103,35 @@ class AutresEncaissementsController extends AdminController
|
||||
$notificationMessage = "Nouvel encaissement {$finalType} créé par {$user['firstname']} {$user['lastname']} - Montant: {$montantFormate} Ar";
|
||||
|
||||
// ✅ Envoyer notification à DAF, Direction et SuperAdmin de TOUS les stores
|
||||
$Notification->notifyGroupsByPermissionAllStores('notifEncaissement', $notificationMessage, 'encaissements');
|
||||
foreach ($allStores as $store) {
|
||||
$storeId = (int)$store['id'];
|
||||
|
||||
log_message('info', "✅ Encaissement {$encaissementId} créé - Notifications envoyées");
|
||||
// Notification pour DAF
|
||||
$Notification->createNotification(
|
||||
$notificationMessage,
|
||||
"DAF",
|
||||
$storeId,
|
||||
'encaissements'
|
||||
);
|
||||
|
||||
// Log de l'action
|
||||
$historique = new Historique();
|
||||
$historique->logAction('autres_encaissements', 'CREATE', $encaissementId, "Encaissement {$finalType} - Montant: {$montantFormate} Ar");
|
||||
// Notification pour Direction
|
||||
$Notification->createNotification(
|
||||
$notificationMessage,
|
||||
"Direction",
|
||||
$storeId,
|
||||
'encaissements'
|
||||
);
|
||||
|
||||
// Notification pour SuperAdmin
|
||||
$Notification->createNotification(
|
||||
$notificationMessage,
|
||||
"SuperAdmin",
|
||||
$storeId,
|
||||
'encaissements'
|
||||
);
|
||||
}
|
||||
|
||||
log_message('info', "✅ Encaissement {$encaissementId} créé - Notifications envoyées à DAF/Direction/SuperAdmin de tous les stores");
|
||||
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
@ -183,7 +204,30 @@ class AutresEncaissementsController extends AdminController
|
||||
|
||||
$notificationMessage = "Encaissement {$finalType} modifié par {$user['firstname']} {$user['lastname']} - Ancien montant: {$ancienMontant} Ar → Nouveau: {$montantFormate} Ar";
|
||||
|
||||
$Notification->notifyGroupsByPermissionAllStores('notifEncaissement', $notificationMessage, 'encaissements');
|
||||
foreach ($allStores as $store) {
|
||||
$storeId = (int)$store['id'];
|
||||
|
||||
$Notification->createNotification(
|
||||
$notificationMessage,
|
||||
"DAF",
|
||||
$storeId,
|
||||
'encaissements'
|
||||
);
|
||||
|
||||
$Notification->createNotification(
|
||||
$notificationMessage,
|
||||
"Direction",
|
||||
$storeId,
|
||||
'encaissements'
|
||||
);
|
||||
|
||||
$Notification->createNotification(
|
||||
$notificationMessage,
|
||||
"SuperAdmin",
|
||||
$storeId,
|
||||
'encaissements'
|
||||
);
|
||||
}
|
||||
|
||||
log_message('info', "✅ Encaissement {$id} modifié - Notifications envoyées");
|
||||
|
||||
@ -243,7 +287,30 @@ class AutresEncaissementsController extends AdminController
|
||||
|
||||
$notificationMessage = "⚠️ Encaissement {$type} supprimé par {$user['firstname']} {$user['lastname']} - Montant: {$montantFormate} Ar";
|
||||
|
||||
$Notification->notifyGroupsByPermissionAllStores('notifEncaissement', $notificationMessage, 'encaissements');
|
||||
foreach ($allStores as $store) {
|
||||
$storeId = (int)$store['id'];
|
||||
|
||||
$Notification->createNotification(
|
||||
$notificationMessage,
|
||||
"DAF",
|
||||
$storeId,
|
||||
'encaissements'
|
||||
);
|
||||
|
||||
$Notification->createNotification(
|
||||
$notificationMessage,
|
||||
"Direction",
|
||||
$storeId,
|
||||
'encaissements'
|
||||
);
|
||||
|
||||
$Notification->createNotification(
|
||||
$notificationMessage,
|
||||
"SuperAdmin",
|
||||
$storeId,
|
||||
'encaissements'
|
||||
);
|
||||
}
|
||||
|
||||
log_message('info', "✅ Encaissement {$id} supprimé - Notifications envoyées");
|
||||
|
||||
|
||||
@ -116,14 +116,13 @@ private function buildDataRow($value, $product, $isAdmin, $isCommerciale, $isCai
|
||||
{
|
||||
$date_time = date('d-m-Y h:i a', strtotime($value['avance_date']));
|
||||
|
||||
// Gestion du nom du produit et numéro de série
|
||||
$productSku = '';
|
||||
// ✅ Gestion sécurisée du nom du produit
|
||||
if ($value['type_avance'] === 'mere') {
|
||||
$productName = $value['product_name'] ?? 'Produit sur mer';
|
||||
} else {
|
||||
$productData = !empty($value['product_id']) ? $product->find($value['product_id']) : null;
|
||||
$productName = $productData['name'] ?? ($value['product_name'] ?? 'N/A');
|
||||
$productSku = $productData['sku'] ?? '';
|
||||
$productName = !empty($value['product_name'])
|
||||
? $value['product_name']
|
||||
: $product->getProductNameById($value['product_id'] ?? 0);
|
||||
}
|
||||
|
||||
if ($isAdmin) {
|
||||
@ -132,7 +131,6 @@ private function buildDataRow($value, $product, $isAdmin, $isCommerciale, $isCai
|
||||
$value['customer_phone'],
|
||||
$value['customer_address'],
|
||||
$productName,
|
||||
$productSku,
|
||||
number_format((int)$value['gross_amount'], 0, ',', ' '),
|
||||
number_format((int)$value['avance_amount'], 0, ',', ' '),
|
||||
number_format((int)$value['amount_due'], 0, ',', ' '),
|
||||
@ -143,7 +141,6 @@ private function buildDataRow($value, $product, $isAdmin, $isCommerciale, $isCai
|
||||
return [
|
||||
$value['avance_id'],
|
||||
$productName,
|
||||
$productSku,
|
||||
number_format((int)$value['avance_amount'], 0, ',', ' '),
|
||||
number_format((int)$value['amount_due'], 0, ',', ' '),
|
||||
$date_time,
|
||||
@ -198,75 +195,7 @@ private function fetchAvanceDataGeneric($methodName = 'getAllAvanceData')
|
||||
|
||||
public function fetchAvanceBecameOrder()
|
||||
{
|
||||
helper(['url', 'form']);
|
||||
$Avance = new Avance();
|
||||
$product = new Products();
|
||||
$result = ['data' => []];
|
||||
|
||||
$data = $Avance->getCompletedAvances();
|
||||
$session = session();
|
||||
$users = $session->get('user');
|
||||
|
||||
$isAdmin = $this->isAdmin($users);
|
||||
$isCommerciale = $this->isCommerciale($users);
|
||||
$isCaissier = $this->isCaissier($users);
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
$isOwner = $users['id'] === $value['user_id'];
|
||||
|
||||
$buttons = $this->buildActionButtons(
|
||||
$value,
|
||||
$isAdmin,
|
||||
$isOwner,
|
||||
$isCaissier,
|
||||
$isCommerciale
|
||||
);
|
||||
|
||||
// Déterminer le statut
|
||||
if ($value['is_order'] == 1) {
|
||||
$status = '<span class="label label-success"><i class="fa fa-check"></i> Payé</span>';
|
||||
} else {
|
||||
$status = '<span class="label label-warning"><i class="fa fa-clock-o"></i> En attente de paiement</span>';
|
||||
}
|
||||
|
||||
$date_time = date('d-m-Y h:i a', strtotime($value['avance_date']));
|
||||
|
||||
$productSku = '';
|
||||
if ($value['type_avance'] === 'mere') {
|
||||
$productName = $value['product_name'] ?? 'Produit sur mer';
|
||||
} else {
|
||||
$productData = !empty($value['product_id']) ? $product->find($value['product_id']) : null;
|
||||
$productName = $productData['name'] ?? ($value['product_name'] ?? 'N/A');
|
||||
$productSku = $productData['sku'] ?? '';
|
||||
}
|
||||
|
||||
if ($isAdmin) {
|
||||
$result['data'][] = [
|
||||
$value['customer_name'],
|
||||
$value['customer_phone'],
|
||||
$value['customer_address'],
|
||||
$productName,
|
||||
$productSku,
|
||||
number_format((int)$value['gross_amount'], 0, ',', ' '),
|
||||
number_format((int)$value['avance_amount'], 0, ',', ' '),
|
||||
$status,
|
||||
$date_time,
|
||||
$buttons,
|
||||
];
|
||||
} elseif ($isCommerciale || $isCaissier) {
|
||||
$result['data'][] = [
|
||||
$value['avance_id'],
|
||||
$productName,
|
||||
$productSku,
|
||||
number_format((int)$value['avance_amount'], 0, ',', ' '),
|
||||
$status,
|
||||
$date_time,
|
||||
$buttons,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response->setJSON($result);
|
||||
return $this->fetchAvanceDataGeneric('getCompletedAvances');
|
||||
}
|
||||
|
||||
public function fetchExpiredAvance()
|
||||
@ -389,11 +318,28 @@ public function validateAvance()
|
||||
$customerName = $avance['customer_name'];
|
||||
$avanceNumber = str_pad($avance['avance_id'], 5, '0', STR_PAD_LEFT);
|
||||
|
||||
// Notifier les commerciaux
|
||||
$Notification->notifyGroupsByPermission('notifRemise', "✅ Votre avance N°{$avanceNumber} pour le client {$customerName} a été validée par la caissière", (int)$users['store_id'], 'avances');
|
||||
// Notifier le commercial
|
||||
$Notification->createNotification(
|
||||
"✅ Votre avance N°{$avanceNumber} pour le client {$customerName} a été validée par la caissière",
|
||||
"COMMERCIALE",
|
||||
(int)$users['store_id'],
|
||||
'avances'
|
||||
);
|
||||
|
||||
// Notifier les groupes ayant updateAvance
|
||||
$Notification->notifyGroupsByPermission('notifAvance', "La caissière a validé l'avance N°{$avanceNumber} créée par un commercial", (int)$users['store_id'], 'avances');
|
||||
// Notifier Direction/DAF
|
||||
$Notification->createNotification(
|
||||
"La caissière a validé l'avance N°{$avanceNumber} créée par un commercial",
|
||||
"Direction",
|
||||
(int)$users['store_id'],
|
||||
'avances'
|
||||
);
|
||||
|
||||
$Notification->createNotification(
|
||||
"La caissière a validé l'avance N°{$avanceNumber} créée par un commercial",
|
||||
"DAF",
|
||||
(int)$users['store_id'],
|
||||
'avances'
|
||||
);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
@ -619,7 +565,7 @@ public function validateAvance()
|
||||
{
|
||||
$this->verifyRole('createAvance');
|
||||
|
||||
if (strtolower($this->request->getMethod()) !== 'post') {
|
||||
if ($this->request->getMethod() !== 'post') {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'messages' => 'Méthode non autorisée'
|
||||
@ -726,12 +672,43 @@ public function validateAvance()
|
||||
|
||||
$notificationMessage = "Nouvelle avance {$typeAvanceLabel} créée par {$users['firstname']} {$users['lastname']} - Client: {$customerName} - Montant: {$avanceAmount} Ar";
|
||||
|
||||
// ✅ Notifier tous les groupes ayant updateAvance de TOUS les stores
|
||||
$Notification->notifyGroupsByPermissionAllStores('notifAvance', $notificationMessage, 'avances');
|
||||
// ✅ 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,
|
||||
'avances'
|
||||
);
|
||||
|
||||
// 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)) {
|
||||
$Notification->notifyGroupsByPermission('notifSortieCaisse', 'Une nouvelle avance a été créée par un commercial', (int)$users['store_id'], 'avances');
|
||||
$Notification->createNotification(
|
||||
'Une nouvelle avance a été créée par un commercial',
|
||||
"Caissière",
|
||||
(int)$users['store_id'],
|
||||
'avances'
|
||||
);
|
||||
}
|
||||
|
||||
log_message('info', "✅ Avance {$avance_id} créée - Notifications envoyées à DAF/Direction/SuperAdmin de tous les stores");
|
||||
@ -760,7 +737,7 @@ public function validateAvance()
|
||||
{
|
||||
$this->verifyRole('updateAvance');
|
||||
|
||||
if (strtolower($this->request->getMethod()) !== 'post') {
|
||||
if ($this->request->getMethod() !== 'post') {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'messages' => 'Méthode non autorisée'
|
||||
@ -924,7 +901,12 @@ public function validateAvance()
|
||||
}
|
||||
|
||||
// ✅ NOTIFICATION (modification simple)
|
||||
$Notification->notifyGroupsByPermission('notifSortieCaisse', 'Une avance a été modifiée', (int)$users['store_id'], 'avances');
|
||||
$Notification->createNotification(
|
||||
'Une avance a été modifiée',
|
||||
"Caissière",
|
||||
(int)$users['store_id'],
|
||||
'avances'
|
||||
);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
@ -1069,21 +1051,13 @@ public function printInvoice($avance_id)
|
||||
return redirect()->back()->with('error', 'Accès non autorisé');
|
||||
}
|
||||
|
||||
// Récupérer les données de l'entreprise
|
||||
$companyModel = new Company();
|
||||
$companyData = $companyModel->getCompanyData(1);
|
||||
|
||||
// Récupérer les détails du produit
|
||||
$product = null;
|
||||
$brandName = '';
|
||||
// ✅ CORRECTION SIMPLIFIÉE
|
||||
if ($avance['type_avance'] === 'mere' && !empty($avance['product_name'])) {
|
||||
$productName = $avance['product_name'];
|
||||
$productDetails = [
|
||||
'marque' => $avance['product_name'],
|
||||
'numero_moteur' => '',
|
||||
'puissance' => '',
|
||||
'couleur' => '',
|
||||
'chasis' => '',
|
||||
'type_avance' => 'mere',
|
||||
'puissance' => ''
|
||||
];
|
||||
} else {
|
||||
$product = $Products->find($avance['product_id']);
|
||||
@ -1092,6 +1066,9 @@ public function printInvoice($avance_id)
|
||||
return redirect()->back()->with('error', 'Produit non trouvé');
|
||||
}
|
||||
|
||||
$productName = $product['name'] ?? 'N/A';
|
||||
|
||||
// ✅ Récupérer le nom de la marque
|
||||
$brandName = 'N/A';
|
||||
if (!empty($product['marque'])) {
|
||||
$db = \Config\Database::connect();
|
||||
@ -1108,14 +1085,11 @@ public function printInvoice($avance_id)
|
||||
$productDetails = [
|
||||
'marque' => $brandName,
|
||||
'numero_moteur' => $product['numero_de_moteur'] ?? '',
|
||||
'puissance' => $product['puissance'] ?? '',
|
||||
'couleur' => $product['cler'] ?? '',
|
||||
'chasis' => $product['chasis'] ?? '',
|
||||
'type_avance' => $avance['type_avance'] ?? 'terre',
|
||||
'puissance' => $product['puissance'] ?? ''
|
||||
];
|
||||
}
|
||||
|
||||
$html = $this->generatePrintableInvoiceHTML($avance, $productDetails, $companyData);
|
||||
$html = $this->generatePrintableInvoiceHTML($avance, $productName, $productDetails);
|
||||
|
||||
return $this->response->setBody($html);
|
||||
|
||||
@ -1782,9 +1756,23 @@ public function notifyPrintInvoice()
|
||||
$customerName = $avance['customer_name'];
|
||||
$avanceNumber = str_pad($avance['avance_id'], 5, '0', STR_PAD_LEFT);
|
||||
|
||||
$Notification->notifyGroupsByPermission(
|
||||
'updateAvance',
|
||||
"La caissière a imprimé la facture avance N°{$avanceNumber} pour le client {$customerName}",
|
||||
$Notification->createNotification(
|
||||
"La caissière a imprimé la facture N°{$avanceNumber} pour le client {$customerName}",
|
||||
"Direction",
|
||||
(int)$users['store_id'],
|
||||
'avances'
|
||||
);
|
||||
|
||||
$Notification->createNotification(
|
||||
"Il y a une avance N°{$avanceNumber} pour le client {$customerName}",
|
||||
"DAF",
|
||||
(int)$users['store_id'],
|
||||
'avances'
|
||||
);
|
||||
|
||||
$Notification->createNotification(
|
||||
"Il y a une avance N°{$avanceNumber} pour le client {$customerName}",
|
||||
"SuperAdmin",
|
||||
(int)$users['store_id'],
|
||||
'avances'
|
||||
);
|
||||
@ -1900,34 +1888,19 @@ public function getFullInvoiceForPrint($avance_id)
|
||||
/**
|
||||
* Générer le HTML optimisé pour l'impression (version identique à printInvoice)
|
||||
*/
|
||||
private function generatePrintableInvoiceHTML($avance, $productDetails, $companyData)
|
||||
private function generatePrintableInvoiceHTML($avance, $productName, $productDetails)
|
||||
{
|
||||
$avanceDate = date('d/m/Y', strtotime($avance['avance_date']));
|
||||
$avanceNumber = str_pad($avance['avance_id'], 5, '0', STR_PAD_LEFT);
|
||||
$customerName = strtoupper(esc($avance['customer_name']));
|
||||
$customerPhone = esc($avance['customer_phone'] ?? '');
|
||||
$customerPhone = esc($avance['customer_phone']);
|
||||
$customerCin = esc($avance['customer_cin']);
|
||||
$grossAmount = number_format($avance['gross_amount'], 0, ',', ' ');
|
||||
$avanceAmount = number_format($avance['avance_amount'], 0, ',', ' ');
|
||||
$amountDue = number_format($avance['amount_due'], 0, ',', ' ');
|
||||
$marque = esc($productDetails['marque']);
|
||||
$marque = esc($productDetails['marque']) ?: $productName;
|
||||
$numeroMoteur = esc($productDetails['numero_moteur']);
|
||||
$puissance = esc($productDetails['puissance']);
|
||||
$couleur = esc($productDetails['couleur'] ?? '');
|
||||
$chasis = esc($productDetails['chasis'] ?? '');
|
||||
$typeAvance = $productDetails['type_avance'] ?? 'terre';
|
||||
$nSerieOuArrivage = ($typeAvance === 'mere') ? 'Arrivage' : ($chasis ?: $numeroMoteur);
|
||||
$typePayment = esc($avance['type_payment'] ?? '');
|
||||
$unite = '1';
|
||||
|
||||
// Company data
|
||||
$companyName = esc($companyData['company_name'] ?? 'MOTORBIKE STORE');
|
||||
$companyNIF = esc($companyData['NIF'] ?? '');
|
||||
$companySTAT = esc($companyData['STAT'] ?? '');
|
||||
$companyPhone = esc($companyData['phone'] ?? '');
|
||||
$companyPhone2 = esc($companyData['phone2'] ?? '');
|
||||
$companyAddress = esc($companyData['address'] ?? '');
|
||||
|
||||
$year = date('Y');
|
||||
|
||||
return <<<HTML
|
||||
<!DOCTYPE html>
|
||||
@ -1935,7 +1908,7 @@ private function generatePrintableInvoiceHTML($avance, $productDetails, $company
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Facture d'Acompte - {$companyName}</title>
|
||||
<title>Facture Avance - KELY SCOOTERS</title>
|
||||
<style>
|
||||
@media print {
|
||||
body { margin: 0; padding: 0; }
|
||||
@ -1948,347 +1921,276 @@ private function generatePrintableInvoiceHTML($avance, $productDetails, $company
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.page {
|
||||
width: 210mm;
|
||||
min-height: 297mm;
|
||||
padding: 15mm 20mm;
|
||||
height: 297mm;
|
||||
padding: 15mm;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* === RECTO === */
|
||||
.recto-title {
|
||||
.invoice-container {
|
||||
border: 2px solid #000;
|
||||
padding: 20px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
margin-bottom: 25px;
|
||||
letter-spacing: 1px;
|
||||
border-bottom: 2px solid #000;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.recto-header {
|
||||
.header h1 {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.header-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 10px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.recto-company {
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
.header-left, .header-right {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.recto-company strong {
|
||||
font-size: 14px;
|
||||
.invoice-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 15px 0;
|
||||
padding: 10px;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
.recto-date-qr {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.recto-date-qr .date-block {
|
||||
font-size: 13px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.qr-code {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.watermark {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) rotate(-25deg);
|
||||
font-size: 60px;
|
||||
color: rgba(0, 0, 0, 0.06);
|
||||
.invoice-title h2 {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 10px;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.recto-body {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
.original-badge {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
padding: 5px 15px;
|
||||
font-weight: bold;
|
||||
transform: skewX(-10deg);
|
||||
}
|
||||
|
||||
.field-line {
|
||||
margin: 12px 0;
|
||||
font-size: 13px;
|
||||
.customer-info {
|
||||
margin: 15px 0;
|
||||
padding: 10px;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
.field-line strong {
|
||||
display: inline-block;
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.field-line .field-value {
|
||||
border-bottom: 1px dotted #000;
|
||||
display: inline-block;
|
||||
min-width: 300px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.field-indent {
|
||||
margin-left: 30px;
|
||||
.customer-info div {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.product-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 25px;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.product-table th, .product-table td {
|
||||
border: 2px solid #000;
|
||||
padding: 10px 12px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
border: 1px solid #000;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.product-table th {
|
||||
background: #f0f0f0;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.product-table td {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
/* === VERSO === */
|
||||
.verso-header {
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.verso-header strong {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.verso-title {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.verso-intro {
|
||||
margin-bottom: 15px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.article {
|
||||
margin: 15px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.article-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.article ul {
|
||||
margin-left: 15px;
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
.article li {
|
||||
margin: 3px 0;
|
||||
}
|
||||
|
||||
.signature-section {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 50px;
|
||||
margin-top: auto;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.signature-box {
|
||||
width: 40%;
|
||||
border: 2px solid #000;
|
||||
min-height: 80px;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
.signature-box .sig-title {
|
||||
.signature-box p {
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
margin-bottom: 60px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
/* Style spécifique pour le verso */
|
||||
.contract-section {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
border: 2px solid #000;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.contract-section h3 {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
margin-bottom: 10px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.contract-article {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.contract-article strong {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.verso-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- ==================== RECTO ==================== -->
|
||||
<!-- RECTO -->
|
||||
<div class="page">
|
||||
<div class="watermark">ORIGINAL</div>
|
||||
|
||||
<div class="recto-title">FACTURE D'ACOMPTE DE RESERVATION</div>
|
||||
|
||||
<div class="recto-header">
|
||||
<div class="recto-company">
|
||||
<strong>{$companyName}</strong><br>
|
||||
NIF : {$companyNIF}<br>
|
||||
STAT : {$companySTAT}<br>
|
||||
Contact : {$companyPhone} / {$companyPhone2}<br>
|
||||
{$companyAddress}
|
||||
<div class="invoice-container">
|
||||
<!-- Header -->
|
||||
<div class="header">
|
||||
<h1>KELY SCOOTERS</h1>
|
||||
<div class="header-info">
|
||||
<div class="header-left">
|
||||
<div>NIF: 401 840 5554</div>
|
||||
<div>STAT: 46101 11 2024 00317</div>
|
||||
</div>
|
||||
<div class="recto-date-qr">
|
||||
<div class="date-block">
|
||||
Date : <strong>{$avanceDate}</strong><br>
|
||||
N° : <strong>{$avanceNumber}</strong>
|
||||
<div class="header-right">
|
||||
<div>Contact: +261 34 27 946 35 / +261 34 07 079 69</div>
|
||||
<div>Antsakaviro en face WWF</div>
|
||||
</div>
|
||||
<canvas id="qrcode" class="qr-code"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="recto-body">
|
||||
<div class="field-line"><strong>DOIT</strong></div>
|
||||
|
||||
<div class="field-line">
|
||||
<strong>NOM :</strong>
|
||||
<span class="field-value">{$customerName}</span>
|
||||
<!-- Invoice Title -->
|
||||
<div class="invoice-title">
|
||||
<div>
|
||||
<h2>FACTURE</h2>
|
||||
<div>Date: {$avanceDate}</div>
|
||||
<div>N°: {$avanceNumber}CI 2025</div>
|
||||
</div>
|
||||
<div class="original-badge">DOIT ORIGINAL</div>
|
||||
</div>
|
||||
|
||||
<div class="field-line">
|
||||
<strong>N de Série ou Arrivage :</strong>
|
||||
<span class="field-value">{$nSerieOuArrivage}</span>
|
||||
<!-- Customer Info -->
|
||||
<div class="customer-info">
|
||||
<div><strong>NOM:</strong> {$customerName} ({$customerPhone})</div>
|
||||
<div><strong>CIN:</strong> {$customerCin}</div>
|
||||
<div><strong>PC:</strong> {$grossAmount} Ar</div>
|
||||
<div><strong>AVANCE:</strong> {$avanceAmount} Ar</div>
|
||||
<div><strong>RAP:</strong> {$amountDue} Ar</div>
|
||||
</div>
|
||||
|
||||
<div class="field-line field-indent">
|
||||
Si Arrivage, préciser la caractéristique de la moto : Couleur
|
||||
<span class="field-value">{$couleur}</span>
|
||||
</div>
|
||||
|
||||
<div class="field-line">
|
||||
<strong>MOTO :</strong>
|
||||
<span class="field-value">{$marque}</span>
|
||||
</div>
|
||||
|
||||
<div class="field-line field-indent">
|
||||
<strong>Unité :</strong>
|
||||
<span class="field-value">{$unite}</span>
|
||||
</div>
|
||||
|
||||
<div class="field-line field-indent">
|
||||
<strong>Prix Unitaire :</strong>
|
||||
<span class="field-value">{$grossAmount} Ar</span>
|
||||
</div>
|
||||
|
||||
<div class="field-line">
|
||||
<strong>Montant Total :</strong>
|
||||
<span class="field-value">{$grossAmount} Ar</span>
|
||||
</div>
|
||||
|
||||
<div class="field-line">
|
||||
<strong>Mode de Paiement :</strong>
|
||||
<span class="field-value">{$typePayment}</span>
|
||||
</div>
|
||||
|
||||
<div class="field-line">
|
||||
<strong>AVANCE :</strong>
|
||||
<span class="field-value">{$avanceAmount} Ar</span>
|
||||
</div>
|
||||
|
||||
<div class="field-line">
|
||||
<strong>Reste à payer :</strong>
|
||||
<span class="field-value">{$amountDue} Ar</span>
|
||||
</div>
|
||||
|
||||
<!-- Tableau récapitulatif -->
|
||||
<!-- Product Table -->
|
||||
<table class="product-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>MARQUE</th>
|
||||
<th>N° Châssis/Arrivage</th>
|
||||
<th>N°MOTEUR</th>
|
||||
<th>PUISSANCE</th>
|
||||
<th>Reste à payer (Ariary)</th>
|
||||
<th>RAP (Ariary)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{$marque}</td>
|
||||
<td>{$chasis}</td>
|
||||
<td>{$numeroMoteur}</td>
|
||||
<td>{$puissance}</td>
|
||||
<td>{$amountDue}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== VERSO ==================== -->
|
||||
<!-- VERSO -->
|
||||
<div class="page">
|
||||
<div class="verso-header">
|
||||
<strong>{$companyName}</strong><br>
|
||||
NIF : {$companyNIF}<br>
|
||||
STAT : {$companySTAT}<br>
|
||||
Contact : {$companyPhone} / {$companyPhone2}<br>
|
||||
{$companyAddress}
|
||||
<div class="invoice-container">
|
||||
|
||||
|
||||
<div class="invoice-title">
|
||||
<div>
|
||||
<h2>CONDITIONS GÉNÉRALES</h2>
|
||||
<div>Date: {$avanceDate}</div>
|
||||
<div>N°: {$avanceNumber}CI 2025</div>
|
||||
|
||||
<div class="verso-content">
|
||||
<!-- Contract Section -->
|
||||
<div class="contract-section">
|
||||
<h3>FIFANEKENA ARA-BAROTRA (Réservations)</h3>
|
||||
<p><strong>Ry mpanjifa hajaina,</strong></p>
|
||||
<p>Natao ity fifanekena ity mba hialana amin'ny fivadihana hampitokisana amin'ny andaniny sy ankilany.</p>
|
||||
|
||||
<div class="contract-article">
|
||||
<strong>Andininy faha-1: FAMANDRAHANA SY FANDOAVAM-BOLA</strong>
|
||||
<p>Ny mpividy dia manao famandrahana amin'ny alalan'ny fandoavambola mihoatra ny 25 isan-jato amin'ny vidin'entana rehetra (avances).</p>
|
||||
</div>
|
||||
|
||||
<div class="verso-title">FIFANEKENA ARA-BAROTRA (Reservations)</div>
|
||||
|
||||
<div class="verso-intro">
|
||||
Ry mpanjifa hajaina,<br><br>
|
||||
Natao ity fifanekena ity mba hialana amin'ny fivadiahampitokisana amin'ny andaniny sy ankilany.
|
||||
<div class="contract-article">
|
||||
<strong>Andininy faha-2: FANDOAVAM-BOLA REHEFA TONGA NY ENTANA (ARRIVAGE)</strong>
|
||||
<p>Rehefa tonga ny moto/pieces dia tsy maintsy mandoa ny 50 isan-jato ny vidin'entana ny mpamandrika.</p>
|
||||
<p>Manana 15 andro kosa adoavana ny 25 isan-jato raha misy tsy fahafahana alohan'ny famoahana ny entana.</p>
|
||||
</div>
|
||||
|
||||
<div class="article">
|
||||
<div class="article-title">• Andininy faha-1 : FAMANDRIHANA SY FANDOAVAM-BOLA</div>
|
||||
<p>Ny mpividy dia manao famandrihana amin'ny alalan'ny fandoavam-bola mihoatra ny 25 isan-jato amin'ny vidin'entana rehetra (avances).</p>
|
||||
</div>
|
||||
|
||||
<div class="article">
|
||||
<div class="article-title">• Andininy faha-2 : FANDOAVAM-BOLA REHEFA TONGA NY ENTANA (ARRIVAGE)</div>
|
||||
<p>Rehefa tonga ny moto/pieces dia tsy maintsy mandoha ny 50 isan-jato ny vidin'entana ny mpamandrika.</p>
|
||||
<p>Manana 15 andro kosa andoaovana ny 25 isan-jato raha misy tsy fahafahana alohan'ny famoahana ny entana.</p>
|
||||
</div>
|
||||
|
||||
<div class="article">
|
||||
<div class="article-title">• Andininy faha-3 : FAMERENANA VOLA</div>
|
||||
<div class="contract-article">
|
||||
<strong>Andininy faha-3: FAMERENANA VOLA</strong>
|
||||
<p>Raha toa ka misy antony tsy hakana ny entana indray dia tsy mamerina ny vola efa voaloha (avance) ny société.</p>
|
||||
</div>
|
||||
|
||||
<div class="article">
|
||||
<div class="article-title">• Andininy faha-4 : FEPETRA FANAMPINY</div>
|
||||
<ul>
|
||||
<div class="contract-article">
|
||||
<strong>Andininy faha-4: FEPETRA FANAMPINY</strong>
|
||||
<ul style="margin-left: 20px;">
|
||||
<li>Tsy misafidy raha toa ka mamafa no ifanarahana.</li>
|
||||
<li>Tsy azo atao ny mamerina vola efa naloha.</li>
|
||||
<li>Tsy azo atao ny manakalo ny entana efa nofandrihana.</li>
|
||||
<li>Tsy azo atao ny mamerina ny entana efa nofandrahana.</li>
|
||||
<li>Tsy azo atao ny manakalo ny entana efa nofandrahana.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Signatures -->
|
||||
<!-- Additional space for notes -->
|
||||
<div style="margin-top: 20px; padding: 10px; border: 1px solid #000; flex: 1;">
|
||||
<strong>OBSERVATIONS / NOTES:</strong>
|
||||
<div style="height: 100px; margin-top: 10px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- Signatures for verso -->
|
||||
<div class="signature-section">
|
||||
<div class="signature-box">
|
||||
<div class="sig-title">NY MPAMANDRIKA</div>
|
||||
<p>NY MPAMANDRIKA</p>
|
||||
<div style="border-top: 1px solid #000; padding-top: 5px;">Signature</div>
|
||||
</div>
|
||||
<div class="signature-box">
|
||||
<p>NY MPIVAROTRA</p>
|
||||
<div style="border-top: 1px solid #000; padding-top: 5px;">
|
||||
<strong>KELY SCOOTERS</strong><br>
|
||||
NIF: 401 840 5554
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="signature-box" style="text-align: right;">
|
||||
<div class="sig-title">NY MPIVAROTRA</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- QR Code JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/qrious@4.0.2/dist/qrious.min.js"></script>
|
||||
<script>
|
||||
new QRious({
|
||||
element: document.getElementById('qrcode'),
|
||||
value: "FACTURE D'ACOMPTE DE RESERVATION\\nN° {$avanceNumber}\\nClient: {$customerName}\\nMontant Total: {$grossAmount} Ar\\nAvance: {$avanceAmount} Ar\\nReste: {$amountDue} Ar\\nDate: {$avanceDate}\\nFacebook: https://www.facebook.com/MOTORBIKESTORE2021/",
|
||||
size: 100,
|
||||
level: 'H'
|
||||
});
|
||||
window.onload = function() { window.print(); };
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
|
||||
@ -100,7 +100,7 @@ class AvanceController extends AdminController
|
||||
$Products = new Products();
|
||||
$Notification = New NotificationController();
|
||||
|
||||
if (strtolower($this->request->getMethod()) === 'post' && $validation->run($validationData)) {
|
||||
if ($this->request->getMethod() === 'post' && $validation->run($validationData)) {
|
||||
$session = session();
|
||||
$users = $session->get('user');
|
||||
|
||||
@ -120,7 +120,7 @@ class AvanceController extends AdminController
|
||||
$posts = $products;
|
||||
|
||||
if($avance_id = $Avance->createAvance($data)){
|
||||
$Notification->notifyGroupsByPermission('notifAvance', 'Une avance a été créé', $users['store_id'], 'avance');
|
||||
$Notification->createNotification('Une avance a été créé', "Conseil",$users['store_id'], 'avance');
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'messages' => 'Avance créé avec succès !'
|
||||
@ -143,7 +143,7 @@ class AvanceController extends AdminController
|
||||
$Products = new Products();
|
||||
$Avance = new Avance();
|
||||
|
||||
if (strtolower($this->request->getMethod()) === 'post') {
|
||||
if ($this->request->getMethod() === 'post') {
|
||||
$data = [
|
||||
'customer_name' => $this->request->getPost('customer_name_avance'),
|
||||
'customer_address'=> $this->request->getPost('customer_address_avance'),
|
||||
|
||||
@ -29,7 +29,7 @@ class CompanyController extends AdminController
|
||||
|
||||
$Company = new Company();
|
||||
// die(var_dump($validation->getErrors()));
|
||||
if (strtolower($this->request->getMethod()) === 'post' && $validation->withRequest($this->request)->run()) {
|
||||
if ($this->request->getMethod() == 'post' && $validation->withRequest($this->request)->run()) {
|
||||
// If the form is valid
|
||||
$data = [
|
||||
'company_name' => $this->request->getPost('company_name'),
|
||||
@ -45,14 +45,6 @@ class CompanyController extends AdminController
|
||||
'currency' => $this->request->getPost('currency'),
|
||||
];
|
||||
|
||||
// Upload du logo
|
||||
$logoFile = $this->request->getFile('logo');
|
||||
if ($logoFile && $logoFile->isValid() && !$logoFile->hasMoved()) {
|
||||
$newName = 'company_logo.' . $logoFile->getExtension();
|
||||
$logoFile->move(FCPATH . 'assets/images/', $newName, true);
|
||||
$data['logo'] = 'assets/images/' . $newName;
|
||||
}
|
||||
|
||||
if ($Company->updateCompany($data, 1)) {
|
||||
session()->setFlashdata('success', 'Successfully updated');
|
||||
return redirect()->to('/company');
|
||||
|
||||
@ -284,89 +284,4 @@ class Dashboard extends AdminController
|
||||
return $this->render_template('dashboard', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX : Recalculer la trésorerie avec filtre de dates
|
||||
*/
|
||||
public function getTresorerieData()
|
||||
{
|
||||
$session = session();
|
||||
$user_id = $session->get('user');
|
||||
|
||||
$startDate = $this->request->getGet('start_date');
|
||||
$endDate = $this->request->getGet('end_date');
|
||||
|
||||
$orderModel = new Orders();
|
||||
$Avance = new Avance();
|
||||
$sortieCaisse = new SortieCaisse();
|
||||
$Recouvrement = new Recouvrement();
|
||||
$autresEncaissementsModel = new AutresEncaissements();
|
||||
|
||||
$isAdmin = in_array($user_id['group_name'], ['DAF', 'Direction', 'SuperAdmin']);
|
||||
$storeIdFilter = $isAdmin ? null : $user_id['store_id'];
|
||||
|
||||
// Données avec filtre de dates
|
||||
$paymentData = $orderModel->getPaymentModes($startDate, $endDate);
|
||||
$totalAvance = $Avance->getTotalAvance($startDate, $endDate);
|
||||
$paymentDataAvance = $Avance->getPaymentModesAvance($startDate, $endDate);
|
||||
$totalRecouvrement = $Recouvrement->getTotalRecouvrements(null, $startDate, $endDate);
|
||||
$total_sortie_caisse = $sortieCaisse->getTotalSortieCaisse($startDate, $endDate);
|
||||
$totauxAutresEncaissements = $autresEncaissementsModel->getTotalEncaissementsByMode($storeIdFilter, $startDate, $endDate);
|
||||
|
||||
// Autres encaissements
|
||||
$total_autres_enc_espece = $totauxAutresEncaissements['total_espece'];
|
||||
$total_autres_enc_mvola = $totauxAutresEncaissements['total_mvola'];
|
||||
$total_autres_enc_virement = $totauxAutresEncaissements['total_virement'];
|
||||
$total_autres_encaissements = $total_autres_enc_espece + $total_autres_enc_mvola + $total_autres_enc_virement;
|
||||
|
||||
// Sorties
|
||||
$total_sortie_espece = isset($total_sortie_caisse->total_espece) ? (float) $total_sortie_caisse->total_espece : 0;
|
||||
$total_sortie_mvola = isset($total_sortie_caisse->total_mvola) ? (float) $total_sortie_caisse->total_mvola : 0;
|
||||
$total_sortie_virement = isset($total_sortie_caisse->total_virement) ? (float) $total_sortie_caisse->total_virement : 0;
|
||||
|
||||
// Recouvrements
|
||||
$me = isset($totalRecouvrement->me) ? (float) $totalRecouvrement->me : 0;
|
||||
$bm = isset($totalRecouvrement->bm) ? (float) $totalRecouvrement->bm : 0;
|
||||
$be = isset($totalRecouvrement->be) ? (float) $totalRecouvrement->be : 0;
|
||||
$mb = isset($totalRecouvrement->mb) ? (float) $totalRecouvrement->mb : 0;
|
||||
|
||||
// Orders
|
||||
$total_orders = isset($paymentData->total) ? (float) $paymentData->total : 0;
|
||||
$mv1_orders = isset($paymentData->total_mvola1) ? (float) $paymentData->total_mvola1 : 0;
|
||||
$mv2_orders = isset($paymentData->total_mvola2) ? (float) $paymentData->total_mvola2 : 0;
|
||||
$es1_orders = isset($paymentData->total_espece1) ? (float) $paymentData->total_espece1 : 0;
|
||||
$es2_orders = isset($paymentData->total_espece2) ? (float) $paymentData->total_espece2 : 0;
|
||||
$vb1_orders = isset($paymentData->total_virement_bancaire1) ? (float) $paymentData->total_virement_bancaire1 : 0;
|
||||
$vb2_orders = isset($paymentData->total_virement_bancaire2) ? (float) $paymentData->total_virement_bancaire2 : 0;
|
||||
|
||||
// Avances
|
||||
$total_avances = isset($paymentDataAvance->total) ? (float) $paymentDataAvance->total : 0;
|
||||
$mv_avances = isset($paymentDataAvance->total_mvola) ? (float) $paymentDataAvance->total_mvola : 0;
|
||||
$es_avances = isset($paymentDataAvance->total_espece) ? (float) $paymentDataAvance->total_espece : 0;
|
||||
$vb_avances = isset($paymentDataAvance->total_virement_bancaire) ? (float) $paymentDataAvance->total_virement_bancaire : 0;
|
||||
|
||||
// Brut
|
||||
$total_mvola_brut = $mv1_orders + $mv2_orders + $mv_avances + $total_autres_enc_mvola;
|
||||
$total_espece_brut = $es1_orders + $es2_orders + $es_avances + $total_autres_enc_espece;
|
||||
$total_vb_brut = $vb1_orders + $vb2_orders + $vb_avances + $total_autres_enc_virement;
|
||||
$total_brut = $total_orders + $total_avances + $total_autres_encaissements;
|
||||
|
||||
// Final
|
||||
$total_sortie_global = $total_sortie_espece + $total_sortie_mvola + $total_sortie_virement;
|
||||
$total_mvola_final = $total_mvola_brut - $me - $mb + $bm - $total_sortie_mvola;
|
||||
$total_espece_final = $total_espece_brut + $me + $be - $total_sortie_espece;
|
||||
$total_vb_final = $total_vb_brut - $be - $bm + $mb - $total_sortie_virement;
|
||||
$total_final = $total_brut - $total_sortie_global;
|
||||
|
||||
return $this->response->setJSON([
|
||||
'total_brut' => number_format($total_brut, 0, '.', ' '),
|
||||
'total_sorties' => number_format($total_sortie_global, 0, '.', ' '),
|
||||
'total_net' => number_format($total_final, 0, '.', ' '),
|
||||
'espece' => number_format($total_espece_final, 0, '.', ' '),
|
||||
'mvola' => number_format($total_mvola_final, 0, '.', ' '),
|
||||
'banque' => number_format($total_vb_final, 0, '.', ' '),
|
||||
'avance_mvola' => number_format($mv_avances, 0, '.', ' '),
|
||||
'avance_espece' => number_format($es_avances, 0, '.', ' '),
|
||||
'avance_banque' => number_format($vb_avances, 0, '.', ' '),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -45,7 +45,7 @@ class GroupController extends AdminController
|
||||
]);
|
||||
|
||||
// Check if form validation is successful
|
||||
if (strtolower($this->request->getMethod()) === 'post') {
|
||||
if ($this->request->getMethod() == 'post') {
|
||||
|
||||
if ($validation->withRequest($this->request)->run()) {
|
||||
|
||||
@ -93,7 +93,7 @@ class GroupController extends AdminController
|
||||
'group_name' => 'required',
|
||||
]);
|
||||
|
||||
if (strtolower($this->request->getMethod()) === 'post') {
|
||||
if ($this->request->getMethod() === 'post') {
|
||||
|
||||
if ($validation->withRequest($this->request)->run()) {
|
||||
// Validation passed
|
||||
@ -149,7 +149,7 @@ class GroupController extends AdminController
|
||||
}
|
||||
|
||||
// Vérifier si c'est une requête POST avec confirmation
|
||||
if (strtolower($this->request->getMethod()) === 'post' && $this->request->getPost('confirm')) {
|
||||
if ($this->request->getMethod() === 'post' && $this->request->getPost('confirm')) {
|
||||
|
||||
// Supprimer d'abord toutes les associations dans user_group
|
||||
$groupsModel->removeUsersFromGroup($id);
|
||||
|
||||
@ -71,7 +71,6 @@ class HistoriqueController extends AdminController
|
||||
$row['product_name'] ?? 'N/A',
|
||||
$row['sku'] ?? 'N/A',
|
||||
$row['store_name'] ?? 'N/A',
|
||||
$row['user_name'] ?? 'N/A',
|
||||
$this->getActionBadge($row['action']),
|
||||
$row['description'] ?? ''
|
||||
];
|
||||
|
||||
@ -3,8 +3,6 @@
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\Notification;
|
||||
use App\Models\Groups;
|
||||
use App\Models\Stores;
|
||||
|
||||
class NotificationController extends AdminController
|
||||
{
|
||||
@ -46,27 +44,6 @@ class NotificationController extends AdminController
|
||||
$Notification->insertNotification($data);
|
||||
}
|
||||
|
||||
// Notifier tous les groupes ayant une permission donnée, pour un store spécifique
|
||||
public function notifyGroupsByPermission(string $permission, string $message, ?int $store_id, ?string $link): void
|
||||
{
|
||||
$groupsModel = new Groups();
|
||||
$groups = $groupsModel->getGroupsWithPermission($permission);
|
||||
foreach ($groups as $group) {
|
||||
$this->createNotification($message, $group['group_name'], $store_id, $link);
|
||||
}
|
||||
}
|
||||
|
||||
// Notifier tous les groupes ayant une permission donnée, pour TOUS les stores actifs
|
||||
public function notifyGroupsByPermissionAllStores(string $permission, string $message, ?string $link): void
|
||||
{
|
||||
$storesModel = new Stores();
|
||||
$allStores = $storesModel->getActiveStore();
|
||||
if (!is_array($allStores) || empty($allStores)) return;
|
||||
foreach ($allStores as $store) {
|
||||
$this->notifyGroupsByPermission($permission, $message, (int)$store['id'], $link);
|
||||
}
|
||||
}
|
||||
|
||||
// Marquer toutes les notifications comme lues pour l'utilisateur connecté
|
||||
public function markAllAsRead()
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -101,20 +101,15 @@ class ProductCOntroller extends AdminController
|
||||
$store_name = $store_info && isset($store_info['name']) ? $store_info['name'] : "Inconnu";
|
||||
}
|
||||
|
||||
// Disponibilité basée sur qty, availability et product_sold
|
||||
$productSold = (int)($value['product_sold'] ?? 0);
|
||||
// Disponibilité basée sur qty ET availability
|
||||
$isInStock = ((int)$value['qty'] > 0);
|
||||
$isAvailable = ((int)$value['availability'] === 1);
|
||||
|
||||
if ($productSold === 2) {
|
||||
$availability = '<span class="label label-warning">En attente de livraison</span>';
|
||||
} elseif ($productSold === 1) {
|
||||
$availability = '<span class="label label-default">Livré</span>';
|
||||
} elseif ($isInStock && $isAvailable) {
|
||||
$availability = '<span class="label label-success">En stock</span>';
|
||||
} else {
|
||||
$availability = '<span class="label label-danger">Rupture</span>';
|
||||
}
|
||||
$isProductAvailable = $isInStock && $isAvailable;
|
||||
|
||||
$availability = $isProductAvailable ?
|
||||
'<span class="label label-success">En stock</span>' :
|
||||
'<span class="label label-danger">Rupture</span>';
|
||||
|
||||
// Construction des boutons
|
||||
$buttons = '';
|
||||
@ -190,7 +185,7 @@ class ProductCOntroller extends AdminController
|
||||
'price_min' => 'required|numeric',
|
||||
]);
|
||||
|
||||
if (strtolower($this->request->getMethod()) === 'post' && $validation->withRequest($this->request)->run()) {
|
||||
if ($this->request->getMethod() === 'post' && $validation->withRequest($this->request)->run()) {
|
||||
|
||||
$prix_min = (float)$this->request->getPost('price_min');
|
||||
$prix_vente = (float)$this->request->getPost('price_vente');
|
||||
@ -229,7 +224,7 @@ class ProductCOntroller extends AdminController
|
||||
'date_arivage' => $this->request->getPost('datea'),
|
||||
'puissance' => $this->request->getPost('puissance'),
|
||||
'cler' => $this->request->getPost('cler'),
|
||||
'categorie_id' => $this->request->getPost('categorie') ? implode(',', $this->request->getPost('categorie')) : '',
|
||||
'categorie_id' => json_encode($this->request->getPost('categorie[]')),
|
||||
'etats' => $this->request->getPost('etats'),
|
||||
'infoManquekit' => $this->request->getPost('infoManquekit'),
|
||||
'info' => $this->request->getPost('info'),
|
||||
@ -248,7 +243,12 @@ class ProductCOntroller extends AdminController
|
||||
]);
|
||||
|
||||
session()->setFlashdata('success', 'Créé avec succès');
|
||||
$Notification->notifyGroupsByPermission('notifProduit', "Un nouveau Produit a été créé", $store_id1, 'products/');
|
||||
$Notification->createNotification(
|
||||
"Un nouveau Produit a été créé",
|
||||
"COMMERCIALE",
|
||||
$store_id1,
|
||||
'products/'
|
||||
);
|
||||
|
||||
return redirect()->to('/products');
|
||||
} else {
|
||||
@ -302,11 +302,6 @@ class ProductCOntroller extends AdminController
|
||||
|
||||
public function update(int $id)
|
||||
{
|
||||
log_message('error', '=== PRODUCT UPDATE CALLED === ID: ' . $id . ' METHOD: ' . $_SERVER['REQUEST_METHOD']);
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
log_message('error', 'POST DATA KEYS: ' . implode(', ', array_keys($_POST)));
|
||||
}
|
||||
|
||||
$Products = new Products();
|
||||
$Stores = new Stores();
|
||||
$Category = new Category();
|
||||
@ -326,32 +321,32 @@ class ProductCOntroller extends AdminController
|
||||
$prix_minimal_data = $FourchettePrix->where('product_id', $id)->first();
|
||||
$prix_minimal = $prix_minimal_data['prix_minimal'] ?? '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $validation->withRequest($this->request)->run()) {
|
||||
if ($this->request->getMethod() === 'post' && $validation->withRequest($this->request)->run()) {
|
||||
|
||||
$availabilityValue = (int)$this->request->getPost('availability');
|
||||
$availability = ($availabilityValue === 1) ? 1 : 0;
|
||||
|
||||
$data = [
|
||||
'name' => $this->request->getPost('nom_de_produit') ?? '',
|
||||
'sku' => $this->request->getPost('numero_de_serie') ?? '',
|
||||
'price' => $this->request->getPost('price') ?? '0',
|
||||
'name' => $this->request->getPost('nom_de_produit'),
|
||||
'sku' => $this->request->getPost('numero_de_serie'),
|
||||
'price' => $this->request->getPost('price'),
|
||||
'qty' => 1,
|
||||
'description' => $this->request->getPost('description') ?? '',
|
||||
'numero_de_moteur' => $this->request->getPost('numero_de_moteur') ?? '',
|
||||
'marque' => $this->request->getPost('marque') ?? '0',
|
||||
'chasis' => $this->request->getPost('chasis') ?? '',
|
||||
'description' => $this->request->getPost('description'),
|
||||
'numero_de_moteur' => $this->request->getPost('numero_de_moteur'),
|
||||
'marque' => $this->request->getPost('marque'),
|
||||
'chasis' => $this->request->getPost('chasis'),
|
||||
'store_id' => (int)$this->request->getPost('store'),
|
||||
'availability'=> $availability,
|
||||
'prix_vente' => $this->request->getPost('price_vente') ?? '0',
|
||||
'date_arivage'=> $this->request->getPost('datea') ?: date('Y-m-d'),
|
||||
'puissance' => $this->request->getPost('puissance') ?? '',
|
||||
'cler' => $this->request->getPost('cler') ?? '',
|
||||
'categorie_id'=> $this->request->getPost('categorie') ? implode(',', $this->request->getPost('categorie')) : '',
|
||||
'etats' => $this->request->getPost('etats') ?? '',
|
||||
'infoManquekit'=> $this->request->getPost('infoManquekit') ?? '',
|
||||
'info' => $this->request->getPost('info') ?? '',
|
||||
'infoManque' => $this->request->getPost('infoManque') ?? '',
|
||||
'type' => $this->request->getPost('type') ?? '',
|
||||
'prix_vente' => $this->request->getPost('price_vente'),
|
||||
'date_arivage'=> $this->request->getPost('datea'),
|
||||
'puissance' => $this->request->getPost('puissance'),
|
||||
'cler' => $this->request->getPost('cler'),
|
||||
'categorie_id'=> json_encode($this->request->getPost('categorie[]')),
|
||||
'etats' => $this->request->getPost('etats'),
|
||||
'infoManquekit'=> $this->request->getPost('infoManquekit'),
|
||||
'info' => $this->request->getPost('info'),
|
||||
'infoManque' => $this->request->getPost('infoManque'),
|
||||
'type' => $this->request->getPost('type'),
|
||||
];
|
||||
|
||||
// ---- GESTION PRIX MINIMAL ----
|
||||
@ -377,41 +372,19 @@ class ProductCOntroller extends AdminController
|
||||
}
|
||||
|
||||
// Upload image si fournie
|
||||
$productImage = $this->request->getFile('product_image');
|
||||
if ($productImage && $productImage->isValid() && !$productImage->hasMoved()) {
|
||||
if ($this->request->getFile('product_image')->isValid()) {
|
||||
$uploadImage = $this->uploadImage();
|
||||
$Products->update($id, ['image' => $uploadImage]);
|
||||
}
|
||||
|
||||
// Mise à jour du produit
|
||||
try {
|
||||
$db = \Config\Database::connect();
|
||||
$session = session();
|
||||
$currentUser = $session->get('user');
|
||||
$userName = ($currentUser['firstname'] ?? '') . ' ' . ($currentUser['lastname'] ?? '');
|
||||
$userId = $currentUser['id'] ?? 0;
|
||||
|
||||
// Passer l'utilisateur au trigger via variables MySQL
|
||||
$db->query("SET @current_user_id = ?", [$userId]);
|
||||
$db->query("SET @current_user_name = ?", [trim($userName)]);
|
||||
|
||||
$builder = $db->table('products');
|
||||
$result = $builder->where('id', $id)->update($data);
|
||||
|
||||
if ($result) {
|
||||
if ($Products->updateProduct($data, $id)) {
|
||||
session()->setFlashdata('success', 'Produit mis à jour avec succès.');
|
||||
return redirect()->to('/products');
|
||||
} else {
|
||||
log_message('error', 'Update produit failed - DB error: ' . $db->error()['message']);
|
||||
session()->setFlashdata('errors', 'Une erreur est survenue lors de la mise à jour.');
|
||||
return redirect()->to('/products/update/' . $id);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
log_message('error', 'Erreur update produit: ' . $e->getMessage());
|
||||
log_message('error', 'Data: ' . json_encode($data));
|
||||
session()->setFlashdata('errors', 'Erreur: ' . $e->getMessage());
|
||||
return redirect()->to('/products/update/' . $id);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Affichage du formulaire
|
||||
|
||||
@ -138,30 +138,24 @@ class RecouvrementController extends AdminController
|
||||
"data" => []
|
||||
];
|
||||
|
||||
$hasActions = in_array('updateRecouvrement', $this->permission) || in_array('deleteRecouvrement', $this->permission);
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
$row = [
|
||||
$buttons = '';
|
||||
if (in_array('updateRecouvrement', $this->permission)) {
|
||||
$buttons .= '<button type="button" class="btn btn-default" onclick="editFunc(' . $value['recouvrement_id'] . ')" data-toggle="modal" data-target="#updateModal"><i class="fa fa-pencil"></i></button>';
|
||||
}
|
||||
|
||||
if (in_array('deleteRecouvrement', $this->permission)) {
|
||||
$buttons .= ' <button type="button" class="btn btn-danger" onclick="removeFunc(' . $value['recouvrement_id'] . ')" data-toggle="modal" data-target="#removeModal"><i class="fa fa-trash"></i></button>';
|
||||
}
|
||||
$result['data'][$key] = [
|
||||
$value['recouvrement_id'],
|
||||
number_format($value['recouvrement_montant'], 0, '.', ' '),
|
||||
$value['recouvrement_date'],
|
||||
$value['recouvrement_personnel'],
|
||||
$value['send_money'],
|
||||
$value['get_money'],
|
||||
$buttons
|
||||
];
|
||||
|
||||
if ($hasActions) {
|
||||
$buttons = '';
|
||||
if (in_array('updateRecouvrement', $this->permission)) {
|
||||
$buttons .= '<button type="button" class="btn btn-default" onclick="editFunc(' . $value['recouvrement_id'] . ')" data-toggle="modal" data-target="#updateModal"><i class="fa fa-pencil"></i></button>';
|
||||
}
|
||||
if (in_array('deleteRecouvrement', $this->permission)) {
|
||||
$buttons .= ' <button type="button" class="btn btn-danger" onclick="removeFunc(' . $value['recouvrement_id'] . ')" data-toggle="modal" data-target="#removeModal"><i class="fa fa-trash"></i></button>';
|
||||
}
|
||||
$row[] = $buttons;
|
||||
}
|
||||
|
||||
$result['data'][$key] = $row;
|
||||
}
|
||||
return $this->response->setJSON($result);
|
||||
}
|
||||
@ -176,30 +170,24 @@ class RecouvrementController extends AdminController
|
||||
"data" => []
|
||||
];
|
||||
|
||||
$hasActions = in_array('updateRecouvrement', $this->permission) || in_array('deleteRecouvrement', $this->permission);
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
$row = [
|
||||
$buttons = '';
|
||||
if (in_array('updateRecouvrement', $this->permission)) {
|
||||
$buttons .= '<button type="button" class="btn btn-default" onclick="editFunc(' . $value['recouvrement_id'] . ')" data-toggle="modal" data-target="#updateModal"><i class="fa fa-pencil"></i></button>';
|
||||
}
|
||||
|
||||
if (in_array('deleteRecouvrement', $this->permission)) {
|
||||
$buttons .= ' <button type="button" class="btn btn-danger" onclick="removeFunc(' . $value['recouvrement_id'] . ')" data-toggle="modal" data-target="#removeModal"><i class="fa fa-trash"></i></button>';
|
||||
}
|
||||
$result['data'][$key] = [
|
||||
$value['recouvrement_id'],
|
||||
number_format($value['recouvrement_montant'], 0, '.', ' '),
|
||||
$value['recouvrement_date'],
|
||||
$value['recouvrement_personnel'],
|
||||
$value['send_money'],
|
||||
$value['get_money'],
|
||||
$buttons
|
||||
];
|
||||
|
||||
if ($hasActions) {
|
||||
$buttons = '';
|
||||
if (in_array('updateRecouvrement', $this->permission)) {
|
||||
$buttons .= '<button type="button" class="btn btn-default" onclick="editFunc(' . $value['recouvrement_id'] . ')" data-toggle="modal" data-target="#updateModal"><i class="fa fa-pencil"></i></button>';
|
||||
}
|
||||
if (in_array('deleteRecouvrement', $this->permission)) {
|
||||
$buttons .= ' <button type="button" class="btn btn-danger" onclick="removeFunc(' . $value['recouvrement_id'] . ')" data-toggle="modal" data-target="#removeModal"><i class="fa fa-trash"></i></button>';
|
||||
}
|
||||
$row[] = $buttons;
|
||||
}
|
||||
|
||||
$result['data'][$key] = $row;
|
||||
}
|
||||
return $this->response->setJSON($result);
|
||||
}
|
||||
@ -233,8 +221,31 @@ class RecouvrementController extends AdminController
|
||||
"Montant: " . number_format($recouvrementData['recouvrement_montant'], 0, ',', ' ') . " Ar<br>" .
|
||||
"Par: " . $users['firstname'] . ' ' . $users['lastname'];
|
||||
|
||||
// ✅ Notifier tous les groupes ayant updateRecouvrement de TOUS les stores
|
||||
$Notification->notifyGroupsByPermissionAllStores('notifRecouvrement', $message, 'recouvrement');
|
||||
// ✅ 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());
|
||||
@ -322,8 +333,34 @@ class RecouvrementController extends AdminController
|
||||
"Store: " . $this->returnStoreName($users['store_id']) . "<br>" .
|
||||
"Par: " . $fullname;
|
||||
|
||||
// ✅ Notifier tous les groupes ayant updateRecouvrement de TOUS les stores
|
||||
$Notification->notifyGroupsByPermissionAllStores('notifRecouvrement', $message, 'recouvrement');
|
||||
// ✅ 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());
|
||||
@ -368,7 +405,7 @@ class RecouvrementController extends AdminController
|
||||
|
||||
$Recouvrement = new Recouvrement();
|
||||
|
||||
if (strtolower($this->request->getMethod()) === 'post') {
|
||||
if ($this->request->getMethod() === 'post') {
|
||||
$data = [
|
||||
'recouvrement_montant' => (int) $this->request->getPost('recouvrement_montant_edit'),
|
||||
'recouvrement_date' => $this->request->getPost('recouvrement_date_edit')
|
||||
@ -389,8 +426,31 @@ class RecouvrementController extends AdminController
|
||||
"Nouveau montant: " . number_format($data['recouvrement_montant'], 0, ',', ' ') . " Ar<br>" .
|
||||
"Par: " . $users['firstname'] . ' ' . $users['lastname'];
|
||||
|
||||
// ✅ Notifier tous les groupes ayant updateRecouvrement de TOUS les stores
|
||||
$Notification->notifyGroupsByPermissionAllStores('notifRecouvrement', $message, 'recouvrement');
|
||||
// ✅ 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());
|
||||
|
||||
@ -5,11 +5,8 @@ namespace App\Controllers;
|
||||
use App\Controllers\AdminController;
|
||||
use App\Models\Notification;
|
||||
use App\Models\Orders;
|
||||
use App\Models\OrderItems;
|
||||
use App\Models\Products;
|
||||
use App\Models\Remise;
|
||||
use App\Models\Stores;
|
||||
use App\Models\Historique;
|
||||
|
||||
class RemiseController extends AdminController
|
||||
{
|
||||
@ -22,10 +19,7 @@ class RemiseController extends AdminController
|
||||
|
||||
public function index()
|
||||
{
|
||||
if (!in_array('viewRemise', $this->permission) && !in_array('validateRemise', $this->permission)) {
|
||||
redirect()->to('/')->send();
|
||||
exit();
|
||||
}
|
||||
$this->verifyRole('viewRemise');
|
||||
|
||||
$data = json_decode($this->fetchTotal(),true);
|
||||
|
||||
@ -64,8 +58,8 @@ class RemiseController extends AdminController
|
||||
foreach ($data as $key => $value) {
|
||||
$buttons = '';
|
||||
|
||||
// ✅ TOUS LES GROUPES AYANT validateRemise PEUVENT VALIDER/REFUSER
|
||||
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 .= '<i class="fa fa-check-circle"></i>';
|
||||
$buttons .= '</button>';
|
||||
@ -75,6 +69,11 @@ class RemiseController extends AdminController
|
||||
$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] = [
|
||||
$value['id_demande'],
|
||||
$value['product'],
|
||||
@ -93,10 +92,19 @@ class RemiseController extends AdminController
|
||||
*/
|
||||
public function updateRemise($id_demande)
|
||||
{
|
||||
$this->verifyRole('validateRemise');
|
||||
|
||||
// ✅ 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');
|
||||
|
||||
$validation = \Config\Services::validation();
|
||||
$data['page_title'] = $this->pageTitle;
|
||||
@ -111,7 +119,7 @@ class RemiseController extends AdminController
|
||||
|
||||
$Remise = new Remise();
|
||||
|
||||
if (strtolower($this->request->getMethod()) === 'post') {
|
||||
if ($this->request->getMethod() == 'post') {
|
||||
$today = date('Y-m-d');
|
||||
$demande_status = $this->request->getPost('demande_status');
|
||||
|
||||
@ -152,35 +160,42 @@ class RemiseController extends AdminController
|
||||
if ($demande_status == 'Refusé') {
|
||||
if ($order_id) {
|
||||
$ordersModel->update($order_id, ['paid_status' => 0]);
|
||||
|
||||
// Libérer les produits de la commande (retour en stock)
|
||||
$orderItemsModel = new OrderItems();
|
||||
$productModel = new Products();
|
||||
$orderItems = $orderItemsModel->getOrdersItemData($order_id);
|
||||
foreach ($orderItems as $item) {
|
||||
if (!empty($item['product_id'])) {
|
||||
$productModel->update($item['product_id'], ['product_sold' => 0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Message de refus
|
||||
$messageRefus = "❌ Demande de remise refusée : {$bill_no}<br>" .
|
||||
"Produit : {$remise_product}<br>" .
|
||||
"Décision : {$user['firstname']} {$user['lastname']} ({$user['group_name']})";
|
||||
"Décision : SuperAdmin";
|
||||
|
||||
// Notifier les commerciaux du store concerné
|
||||
$Notification->notifyGroupsByPermission('notifRemise', $messageRefus . "<br><em>Veuillez modifier la commande.</em>", (int)$store_id, "orders");
|
||||
// Notifier le commercial du store concerné
|
||||
$Notification->createNotification(
|
||||
$messageRefus . "<br><em>Veuillez modifier la commande.</em>",
|
||||
"COMMERCIALE",
|
||||
(int)$store_id,
|
||||
"orders"
|
||||
);
|
||||
|
||||
// ✅ NOTIFIER TOUS LES GROUPES AYANT validateRemise (POUR INFORMATION)
|
||||
$Notification->notifyGroupsByPermissionAllStores('notifRemise', $messageRefus . "<br><em>Pour information</em>", 'remise/');
|
||||
// ✅ 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.';
|
||||
|
||||
// Log refus remise
|
||||
$historique = new Historique();
|
||||
$historique->logAction('remise', 'REFUSE', $id_demande, "Refus de la demande de remise - Facture: {$bill_no}");
|
||||
|
||||
} elseif ($demande_status == 'Accepté' || $demande_status == 'Validé') {
|
||||
// ✅ SI ACCEPTÉ PAR LE SUPERADMIN
|
||||
if ($order_id) {
|
||||
@ -189,22 +204,44 @@ class RemiseController extends AdminController
|
||||
|
||||
$messageAcceptation = "✅ Demande de remise acceptée : {$bill_no}<br>" .
|
||||
"Produit : {$remise_product}<br>" .
|
||||
"Décision : {$user['firstname']} {$user['lastname']} ({$user['group_name']})";
|
||||
"Décision : SuperAdmin";
|
||||
|
||||
// Notifier les caissières du store concerné
|
||||
$Notification->notifyGroupsByPermission('notifSortieCaisse', $messageAcceptation . "<br><em>Commande prête à être traitée</em>", (int)$store_id, "orders");
|
||||
// Notifier la Caissière du store concerné
|
||||
$Notification->createNotification(
|
||||
$messageAcceptation . "<br><em>Commande prête à être traitée</em>",
|
||||
"Caissière",
|
||||
(int)$store_id,
|
||||
"orders"
|
||||
);
|
||||
|
||||
// Notifier les commerciaux du store concerné
|
||||
$Notification->notifyGroupsByPermission('notifRemise', $messageAcceptation, (int)$store_id, "orders");
|
||||
// Notifier le commercial du store concerné
|
||||
$Notification->createNotification(
|
||||
$messageAcceptation,
|
||||
"COMMERCIALE",
|
||||
(int)$store_id,
|
||||
"orders"
|
||||
);
|
||||
|
||||
// ✅ NOTIFIER TOUS LES GROUPES AYANT validateRemise (POUR INFORMATION)
|
||||
$Notification->notifyGroupsByPermissionAllStores('notifRemise', $messageAcceptation . "<br><em>Pour information</em>", 'remise/');
|
||||
// ✅ 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/'
|
||||
);
|
||||
|
||||
$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.';
|
||||
|
||||
// Log validation remise
|
||||
$historique = new Historique();
|
||||
$historique->logAction('remise', 'VALIDATE', $id_demande, "Validation de la demande de remise - Facture: {$bill_no}");
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
|
||||
@ -32,36 +32,13 @@ class ReportController extends AdminController
|
||||
$today_year = $this->request->getPost('select_year');
|
||||
}
|
||||
|
||||
// Récupérer les filtres
|
||||
$startDate = $this->request->getPost('start_date') ?: null;
|
||||
$endDate = $this->request->getPost('end_date') ?: null;
|
||||
$storeId = $this->request->getPost('store_id') ?: null;
|
||||
$userId = $this->request->getPost('user_id') ?: null;
|
||||
|
||||
// Fetch order data and years
|
||||
$Reports = new Reports();
|
||||
$Orders = new Orders();
|
||||
$Store = new Stores();
|
||||
$parking_data = $Reports->getOrderData($today_year, $startDate, $endDate, $storeId, $userId);
|
||||
$parking_data = $Reports->getOrderData($today_year);
|
||||
$data['report_years'] = $Reports->getOrderYear();
|
||||
|
||||
// Charger les stores et users pour les filtres
|
||||
$data['stores'] = $Store->getActiveStore();
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
$data['users_list'] = $db->table('users u')
|
||||
->select('u.id, u.firstname, u.lastname, g.group_name')
|
||||
->join('user_group ug', 'u.id = ug.user_id')
|
||||
->join('groups g', 'ug.group_id = g.id')
|
||||
->whereIn('g.group_name', ['COMMERCIALE', 'Caissière', "Cheffe d'Agence"])
|
||||
->orderBy('u.firstname', 'ASC')
|
||||
->get()->getResultArray();
|
||||
|
||||
// Conserver les filtres sélectionnés
|
||||
$data['selected_start_date'] = $startDate;
|
||||
$data['selected_end_date'] = $endDate;
|
||||
$data['selected_store_id'] = $storeId;
|
||||
$data['selected_user_id'] = $userId;
|
||||
|
||||
// Process the parking data and calculate total amounts
|
||||
$final_parking_data = [];
|
||||
@ -70,6 +47,7 @@ class ReportController extends AdminController
|
||||
|
||||
if (!empty($orders)) {
|
||||
foreach ($orders as $order) {
|
||||
// Utiliser le montant selon la logique : discount si existe, sinon gross_amount
|
||||
if (!empty($order['discount']) && $order['discount'] > 0) {
|
||||
$total_amount_earned += (float) $order['discount'];
|
||||
} else {
|
||||
@ -80,19 +58,18 @@ class ReportController extends AdminController
|
||||
|
||||
$final_parking_data[$month] = $total_amount_earned;
|
||||
}
|
||||
|
||||
// Data for the camembert (pie chart)
|
||||
$paymentModes = $Orders->getPaymentModes($startDate, $endDate, $storeId, $userId);
|
||||
$total_mvola1 = $paymentModes->total_mvola1 ?? 0;
|
||||
$total_mvola2 = $paymentModes->total_mvola2 ?? 0;
|
||||
$total_espece1 = $paymentModes->total_espece1 ?? 0;
|
||||
$total_espece2 = $paymentModes->total_espece2 ?? 0;
|
||||
$total_banque1 = $paymentModes->total_virement_bancaire1 ?? 0;
|
||||
$total_banque2 = $paymentModes->total_virement_bancaire2 ?? 0;
|
||||
$paymentModes = $Orders->getPaymentModes();
|
||||
$total_mvola1 = $paymentModes->total_mvola1;
|
||||
$total_mvola2 = $paymentModes->total_mvola2;
|
||||
$total_espece1 = $paymentModes->total_espece1;
|
||||
$total_espece2 = $paymentModes->total_espece2;
|
||||
$total_banque1 = $paymentModes->total_virement_bancaire1;
|
||||
$total_banque2 = $paymentModes->total_virement_bancaire2;
|
||||
$total_mvola = $total_mvola1 + $total_mvola2;
|
||||
$total_banque = $total_banque1 + $total_banque2;
|
||||
$total_espece = $total_espece1 + $total_espece2;
|
||||
$totalOrders = $Orders->getTotalOrders($startDate, $endDate, $storeId, $userId);
|
||||
$totalOrders = $Orders->getTotalOrders();
|
||||
$totalAmountPerPaymentModes = ["MVOLA" => $total_mvola, "Espece" => $total_espece, "Virement Bancaire" => $total_banque];
|
||||
$totalOrdersCount = (int) $totalOrders->total_orders;
|
||||
$labels = [];
|
||||
@ -110,10 +87,10 @@ class ReportController extends AdminController
|
||||
|
||||
// Prepare data for product chart
|
||||
$OrderItem = new OrderItems();
|
||||
$productTable = $OrderItem->getAllSoldProductToday($startDate, $endDate, $storeId, $userId);
|
||||
$productTable = $OrderItem->getAllSoldProductToday();
|
||||
|
||||
$product_sold = (int) ($productTable->total_product_sold ?? 0);
|
||||
$unsold_product = (int) ($productTable->total_unsold_product ?? 0);
|
||||
$product_sold = (int) $productTable->total_product_sold;
|
||||
$unsold_product = (int) $productTable->total_unsold_product;
|
||||
|
||||
$labels1 = ["Produits vendus", "Produits non vendus"];
|
||||
$totals2 = [$product_sold, $unsold_product];
|
||||
@ -127,8 +104,8 @@ class ReportController extends AdminController
|
||||
$data['results'] = $final_parking_data;
|
||||
|
||||
// Data for the camembert in dashboard
|
||||
$totalStoreOrder = $Orders->getTotalOrderPerStore($startDate, $endDate, $storeId, $userId);
|
||||
$totalOrders = $Orders->getTotalOrders($startDate, $endDate, $storeId, $userId);
|
||||
$totalStoreOrder = $Orders->getTotalOrderPerStore();
|
||||
$totalOrders = $Orders->getTotalOrders();
|
||||
$totalOrdersCount = (int) $totalOrders->total_orders;
|
||||
|
||||
// Initialisation des variables pour éviter l'erreur "Undefined variable"
|
||||
@ -138,7 +115,7 @@ class ReportController extends AdminController
|
||||
foreach ($totalStoreOrder as $totalOrdersInStore) {
|
||||
$storeList = $Store->getStoreById($totalOrdersInStore->store_id);
|
||||
$labelStore[] = $storeList->name ?? 'Inconnu';
|
||||
$totalPerStore[] = ($totalOrdersCount > 0) ? ((int) $totalOrdersInStore->total / $totalOrdersCount) * 100 : 0;
|
||||
$totalPerStore[] = ((int) $totalOrdersInStore->total / $totalOrdersCount) * 100;
|
||||
}
|
||||
|
||||
$data['labelStore'] = json_encode($labelStore);
|
||||
@ -192,13 +169,13 @@ class ReportController extends AdminController
|
||||
{
|
||||
$Orders = new Orders();
|
||||
|
||||
$startDate = $this->request->getGet('startDate');
|
||||
$endDate = $this->request->getGet('endDate');
|
||||
|
||||
$productVente = $Orders->getTotalProductvente2($id, $startDate, $endDate);
|
||||
$productVente = $Orders->getTotalProductvente2($id);
|
||||
$result = ['data' => []];
|
||||
|
||||
foreach ($productVente as $key => $value) {
|
||||
// die(var_dump($value)); // Debugging: Check what $value contains
|
||||
|
||||
// Add the row data
|
||||
$result['data'][$key] = [
|
||||
$value->sku,
|
||||
$value->date_time,
|
||||
@ -206,6 +183,7 @@ class ReportController extends AdminController
|
||||
];
|
||||
}
|
||||
|
||||
// Return data in JSON format
|
||||
return $this->response->setJSON($result);
|
||||
}
|
||||
|
||||
@ -223,7 +201,7 @@ class ReportController extends AdminController
|
||||
{
|
||||
$Products = new Products();
|
||||
|
||||
$produitStock = $Products->getStockByBrand($id);
|
||||
$produitStock = $Products->getProductData2($id);
|
||||
$result = ['data' => []];
|
||||
|
||||
foreach ($produitStock as $key => $value) {
|
||||
@ -245,13 +223,15 @@ class ReportController extends AdminController
|
||||
{
|
||||
$Products = new Orders();
|
||||
|
||||
$startDate = $this->request->getGet('startDate');
|
||||
$endDate = $this->request->getGet('endDate');
|
||||
|
||||
$produitStock = $Products->getOrderVendue($id, $startDate, $endDate);
|
||||
$produitStock = $Products->getOrderVendue();
|
||||
$result = ['data' => []];
|
||||
// echo '<pre>';
|
||||
// die(var_dump($produitStock));
|
||||
|
||||
foreach ($produitStock as $key => $value) {
|
||||
// die(var_dump($value)); // Debugging: Check what $value contains
|
||||
|
||||
// Add the row data
|
||||
$result['data'][$key] = [
|
||||
$value['sku'],
|
||||
$value['qty'],
|
||||
@ -261,6 +241,7 @@ class ReportController extends AdminController
|
||||
];
|
||||
}
|
||||
|
||||
// Return data in JSON format
|
||||
return $this->response->setJSON($result);
|
||||
}
|
||||
|
||||
@ -270,24 +251,10 @@ class ReportController extends AdminController
|
||||
$data['page_title'] = $this->pageTitle;
|
||||
$Stores = new Stores();
|
||||
|
||||
// echo '<pre>';
|
||||
// die(var_dump($orderTest));
|
||||
$data['stores'] = $Stores->getActiveStore();
|
||||
|
||||
// Récupérer les commerciaux et mécaniciens pour les filtres
|
||||
$db = \Config\Database::connect();
|
||||
$data['commerciaux'] = $db->table('users u')
|
||||
->select('u.id, u.firstname, u.lastname')
|
||||
->join('user_group ug', 'u.id = ug.user_id')
|
||||
->join('groups g', 'ug.group_id = g.id')
|
||||
->where('g.group_name', 'COMMERCIALE')
|
||||
->get()->getResultArray();
|
||||
|
||||
$data['mecaniciens'] = $db->table('users u')
|
||||
->select('u.id, u.firstname, u.lastname')
|
||||
->join('user_group ug', 'u.id = ug.user_id')
|
||||
->join('groups g', 'ug.group_id = g.id')
|
||||
->where('g.group_name', 'MECANICIEN')
|
||||
->get()->getResultArray();
|
||||
|
||||
return $this->render_template('reports/performance', $data);
|
||||
}
|
||||
|
||||
@ -298,27 +265,32 @@ class ReportController extends AdminController
|
||||
$session = session();
|
||||
$users = $session->get('user');
|
||||
|
||||
// Récupérer les paramètres de filtre
|
||||
// ✅ RÉCUPÉRER LES PARAMÈTRES DE FILTRE
|
||||
$startDate = $this->request->getGet('startDate');
|
||||
$endDate = $this->request->getGet('endDate');
|
||||
$pvente = $this->request->getGet('pvente');
|
||||
$commercialId = $this->request->getGet('commercial');
|
||||
|
||||
// ✅ CORRECTION : Bonne concaténation des chaînes
|
||||
log_message('debug', 'Filtres Commercial reçus - startDate: ' . $startDate . ', endDate: ' . $endDate . ', pvente: ' . $pvente);
|
||||
|
||||
// Pour Direction et Conseil : afficher TOUTES les performances AVEC FILTRES
|
||||
if ($users['group_name'] === "DAF" || $users['group_name'] === "Direction" || $users['group_name'] === "SuperAdmin") {
|
||||
$orderPaid = $Orders->getPerformanceByOrders($startDate, $endDate, $pvente, $commercialId);
|
||||
// ✅ PASSER LES FILTRES AU MODÈLE - UNIQUEMENT POUR L'ADMIN
|
||||
$orderPaid = $Orders->getPerformanceByOrders($startDate, $endDate, $pvente);
|
||||
foreach ($orderPaid as $key => $value) {
|
||||
// Déterminer le prix de vente réel
|
||||
$prix_vente_reel = (!empty($value['discount']) && $value['discount'] > 0)
|
||||
? $value['discount']
|
||||
: $value['prix_vente'];
|
||||
|
||||
// Calculer le bénéfice
|
||||
$benefice = $prix_vente_reel - $value['price'];
|
||||
|
||||
$result['data'][$key] = [
|
||||
$value['firstname'] . ' ' . $value['lastname'],
|
||||
$value['email'],
|
||||
($value['sku'] == "" ? $value['motoname'] : $value['sku']),
|
||||
(new \DateTime($value['datevente']))->format('Y-m-d'),
|
||||
(new DateTime($value['datevente']))->format('Y-m-d'),
|
||||
number_format($value['price'], 0, '.', ' '),
|
||||
number_format($prix_vente_reel, 0, '.', ' '),
|
||||
$this->returnName($value['store_id']),
|
||||
@ -545,7 +517,7 @@ class ReportController extends AdminController
|
||||
$imageUrl, // 0 - Image
|
||||
$order['bill_no'] ?? 'N/A', // 1 - N° Facture
|
||||
$product['name'], // 2 - Désignation
|
||||
$product['sku'], // 3 - N° SERIE
|
||||
$product['sku'], // 3 - UGS
|
||||
$brandName, // 4 - Marque
|
||||
$order['customer_name'], // 5 - Client
|
||||
$agentName, // 6 - Agent Sécurité
|
||||
|
||||
@ -6,7 +6,6 @@ use App\Models\Securite;
|
||||
use App\Models\Products;
|
||||
use App\Models\Orders;
|
||||
use App\Models\Stores;
|
||||
use App\Models\Historique;
|
||||
|
||||
class SecuriteController extends AdminController
|
||||
{
|
||||
@ -49,7 +48,7 @@ class SecuriteController extends AdminController
|
||||
|
||||
// Bouton d’action
|
||||
$buttons = in_array('validateCommande1', $this->permission)
|
||||
? '<button type="button" class="btn btn-success" onclick="editFunc(' . $securite['id'] . ')"><i class="fa fa-check"></i></button>'
|
||||
? '<button type="button" class="btn btn-success" onclick="editFunc(' . $securite['id'] . ')" data-toggle="modal" data-target="#editModal"><i class="fa fa-check"></i></button>'
|
||||
: '';
|
||||
|
||||
// Statut
|
||||
@ -61,7 +60,7 @@ class SecuriteController extends AdminController
|
||||
|
||||
$result['data'][] = [
|
||||
'image' => $img,
|
||||
'num_serie' => esc($product['sku']),
|
||||
'ugs' => esc($product['sku']),
|
||||
'designation' => esc($product['name']),
|
||||
'statut' => $statut,
|
||||
'action' => $buttons
|
||||
@ -88,7 +87,7 @@ class SecuriteController extends AdminController
|
||||
$response = [
|
||||
'image' => base_url('assets/images/product_image/' . $product['image']),
|
||||
'nom' => $product['name'],
|
||||
'num_serie' => $product['sku'],
|
||||
'ugs' => $product['sku'],
|
||||
'bill_no' => $data['bill_no'],
|
||||
'customer_name' => $order_data['customer_name'],
|
||||
'customer_address' => $order_data['customer_address'],
|
||||
@ -103,7 +102,7 @@ class SecuriteController extends AdminController
|
||||
public function update(int $id)
|
||||
{
|
||||
$this->verifyRole('updateCommande1');
|
||||
$securiteModel = new Securite();
|
||||
$storeModel = new Securite();
|
||||
$post = $this->request->getPost();
|
||||
$response = [];
|
||||
|
||||
@ -115,39 +114,11 @@ class SecuriteController extends AdminController
|
||||
$session = session();
|
||||
$users = $session->get('user');
|
||||
$Notification = new NotificationController();
|
||||
|
||||
if ($securiteModel->updateSecurite($data, $id)) {
|
||||
if ($storeModel->updateSecurite($data, $id)) {
|
||||
if ($post['status'] === "Validé") {
|
||||
// ✅ Récupérer les infos de la ligne securite
|
||||
$securiteData = $securiteModel->getSecuriteData($id);
|
||||
|
||||
if ($securiteData) {
|
||||
// ✅ Marquer le produit comme vendu (product_sold = 1)
|
||||
$productModel = new Products();
|
||||
$productModel->update($securiteData['product_id'], ['product_sold' => 1]);
|
||||
|
||||
// ✅ Mettre à jour la commande liée (paid_status = 3 = livré)
|
||||
if (!empty($securiteData['bill_no'])) {
|
||||
$orderModel = new Orders();
|
||||
$order = $orderModel->getOrdersDataByBillNo($securiteData['bill_no']);
|
||||
if ($order) {
|
||||
$orderModel->update($order['id'], [
|
||||
'paid_status' => 3,
|
||||
'delivered_by' => $users['id'],
|
||||
'delivered_at' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
$Notification->createNotification('Une commande a été validé', "COMMERCIALE",(int)$users['store_id'], 'orders');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$Notification->notifyGroupsByPermission('notifRemise', 'Une commande a été validée et livrée', (int)$users['store_id'], 'orders');
|
||||
}
|
||||
// Log de l'action livraison
|
||||
$historique = new Historique();
|
||||
$billNo = $securiteData['bill_no'] ?? 'N/A';
|
||||
$historique->logAction('securite', 'DELIVERY', $id, "Confirmation de livraison - Facture: {$billNo}");
|
||||
|
||||
$response = ['success' => true, 'messages' => 'Livraison confirmée avec succès'];
|
||||
$response = ['success' => true, 'messages' => 'Mise à jour réussie'];
|
||||
} else {
|
||||
$response = ['success' => false, 'messages' => 'Erreur en base lors de la mise à jour'];
|
||||
}
|
||||
|
||||
@ -574,7 +574,16 @@ public function markAsPaid($id_sortie)
|
||||
"Store: " . $this->returnStoreName($decaissement['store_id']) . "<br>" .
|
||||
"Nouveau solde " . $mode_paiement_label . ": " . number_format($fonds_disponible - $montant_retire, 0, ',', ' ') . " Ar";
|
||||
|
||||
$Notification->notifyGroupsByPermissionAllStores('notifSortieCaisse', $message, 'sortieCaisse');
|
||||
$Stores = new Stores();
|
||||
$allStores = $Stores->getActiveStore();
|
||||
|
||||
if (is_array($allStores) && count($allStores) > 0) {
|
||||
foreach ($allStores as $store) {
|
||||
$Notification->createNotification($message, "Direction", (int)$store['id'], 'sortieCaisse');
|
||||
$Notification->createNotification($message, "DAF", (int)$store['id'], 'sortieCaisse');
|
||||
$Notification->createNotification($message, "SuperAdmin", (int)$store['id'], 'sortieCaisse');
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
log_message('error', 'Erreur notification markAsPaid: ' . $e->getMessage());
|
||||
@ -847,7 +856,16 @@ public function markAsPaid($id_sortie)
|
||||
"Store: " . $this->returnStoreName($user['store_id']) . "<br>" .
|
||||
"Demandeur: " . $user['firstname'] . ' ' . $user['lastname'];
|
||||
|
||||
$Notification->notifyGroupsByPermissionAllStores('notifSortieCaisse', $message, 'sortieCaisse');
|
||||
$Stores = new Stores();
|
||||
$allStores = $Stores->getActiveStore();
|
||||
|
||||
if (is_array($allStores) && count($allStores) > 0) {
|
||||
foreach ($allStores as $store) {
|
||||
$Notification->createNotification($message, "Direction", (int)$store['id'], 'sortieCaisse');
|
||||
$Notification->createNotification($message, "DAF", (int)$store['id'], 'sortieCaisse');
|
||||
$Notification->createNotification($message, "SuperAdmin", (int)$store['id'], 'sortieCaisse');
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
log_message('error', 'Erreur notification createSortieCaisse: ' . $e->getMessage());
|
||||
@ -881,7 +899,7 @@ public function markAsPaid($id_sortie)
|
||||
|
||||
$data['page_title'] = $this->pageTitle;
|
||||
|
||||
if (strtolower($this->request->getMethod()) === 'post') {
|
||||
if ($this->request->getMethod() === 'post') {
|
||||
$validation = \Config\Services::validation();
|
||||
|
||||
$validation->setRules([
|
||||
@ -1014,7 +1032,7 @@ public function markAsPaid($id_sortie)
|
||||
|
||||
$data['page_title'] = $this->pageTitle;
|
||||
|
||||
if (strtolower($this->request->getMethod()) === 'post') {
|
||||
if ($this->request->getMethod() === 'post') {
|
||||
$data = [
|
||||
'admin_raison' => $this->request->getPost('admin_raison'),
|
||||
'statut' => $this->request->getPost('statut'),
|
||||
@ -1036,15 +1054,15 @@ public function markAsPaid($id_sortie)
|
||||
switch ($statut) {
|
||||
case "Valider":
|
||||
$message = "✅ Le décaissement a été validé par la Direction<br>Store: " . $this->returnStoreName($store_id);
|
||||
$Notification->notifyGroupsByPermission('notifSortieCaisse', $message, (int)$store_id, 'sortieCaisse');
|
||||
$Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse');
|
||||
break;
|
||||
case "Refuser":
|
||||
$message = "❌ Le décaissement a été refusé par la Direction<br>Store: " . $this->returnStoreName($store_id) . "<br>Raison: " . $this->request->getPost('admin_raison');
|
||||
$Notification->notifyGroupsByPermission('notifSortieCaisse', $message, (int)$store_id, 'sortieCaisse');
|
||||
$Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse');
|
||||
break;
|
||||
case "En attente":
|
||||
$message = "⏳ Le décaissement a été mis en attente par la Direction<br>Store: " . $this->returnStoreName($store_id);
|
||||
$Notification->notifyGroupsByPermission('notifSortieCaisse', $message, (int)$store_id, 'sortieCaisse');
|
||||
$Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -209,7 +209,7 @@ class UserController extends AdminController
|
||||
$data['page_title'] = $this->pageTitle;
|
||||
|
||||
// Check if it's a POST request before validating
|
||||
if (strtolower($this->request->getMethod()) === 'post') {
|
||||
if ($this->request->getMethod() === 'post') {
|
||||
// Load validation service and run validation
|
||||
if (!$this->validate($validationRules)) {
|
||||
|
||||
@ -285,7 +285,7 @@ class UserController extends AdminController
|
||||
// Check if the ID exists in the request
|
||||
if ($id) {
|
||||
// Check if it's a POST request before validating
|
||||
if (strtolower($this->request->getMethod()) === 'post') {
|
||||
if ($this->request->getMethod() === 'post') {
|
||||
// Validate the form
|
||||
if (!$this->validate($validationRules)) {
|
||||
// Validation failed
|
||||
@ -405,7 +405,7 @@ class UserController extends AdminController
|
||||
]);
|
||||
$Users = new Users();
|
||||
// If validation passes for the first set of rules
|
||||
if (strtolower($this->request->getMethod()) === 'post' && $validation->withRequest($this->request)->run()) {
|
||||
if ($this->request->getMethod() === 'post' && $validation->withRequest($this->request)->run()) {
|
||||
// Handle the case when password is not being updated
|
||||
if (empty($this->request->getPost('password')) && empty($this->request->getPost('cpassword'))) {
|
||||
|
||||
|
||||
@ -189,7 +189,7 @@ class Avance extends Model {
|
||||
}
|
||||
|
||||
// ✅ CORRECTION : getTotalAvance pour la caissière
|
||||
public function getTotalAvance($startDate = null, $endDate = null) {
|
||||
public function getTotalAvance() {
|
||||
$session = session();
|
||||
$users = $session->get('user');
|
||||
$isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction','DAF']);
|
||||
@ -197,16 +197,10 @@ class Avance extends Model {
|
||||
try {
|
||||
$builder = $this->select('SUM(avance_amount) AS ta')
|
||||
->where('is_order', 0)
|
||||
->where('active', 1);
|
||||
->where('active', 1); // ✅ Ajout du filtre active
|
||||
|
||||
if (!$isAdmin) {
|
||||
$builder->where('store_id', $users['store_id']);
|
||||
}
|
||||
if ($startDate) {
|
||||
$builder->where('DATE(avance_date) >=', $startDate);
|
||||
}
|
||||
if ($endDate) {
|
||||
$builder->where('DATE(avance_date) <=', $endDate);
|
||||
$builder->where('store_id', $users['store_id']); // ✅ Filtre par store pour caissière
|
||||
}
|
||||
|
||||
return $builder->get()->getRowObject();
|
||||
@ -218,7 +212,7 @@ class Avance extends Model {
|
||||
|
||||
// ✅ CORRECTION PRINCIPALE : getPaymentModesAvance pour la caissière
|
||||
// ✅ MODIFICATION : Ne compter QUE les avances VALIDÉES
|
||||
public function getPaymentModesAvance($startDate = null, $endDate = null)
|
||||
public function getPaymentModesAvance()
|
||||
{
|
||||
$session = session();
|
||||
$users = $session->get('user');
|
||||
@ -232,19 +226,14 @@ public function getPaymentModesAvance($startDate = null, $endDate = null)
|
||||
SUM(CASE WHEN LOWER(type_payment) = "en espèce" THEN avance_amount ELSE 0 END) AS total_espece,
|
||||
SUM(CASE WHEN LOWER(type_payment) = "virement bancaire" THEN avance_amount ELSE 0 END) AS total_virement_bancaire
|
||||
')
|
||||
->where('validated', 1)
|
||||
->where('validated', 1) // ✅ AJOUT : Uniquement les avances validées
|
||||
->where('active', 1)
|
||||
->where('is_order', 0);
|
||||
|
||||
// ✅ Filtre par store pour non-admin
|
||||
if (!$isAdmin) {
|
||||
$builder->where('store_id', $users['store_id']);
|
||||
}
|
||||
if ($startDate) {
|
||||
$builder->where('DATE(avance_date) >=', $startDate);
|
||||
}
|
||||
if ($endDate) {
|
||||
$builder->where('DATE(avance_date) <=', $endDate);
|
||||
}
|
||||
|
||||
$result = $builder->get()->getRowObject();
|
||||
|
||||
@ -453,11 +442,9 @@ public function getPaymentModesAvance($startDate = null, $endDate = null)
|
||||
$isCommercial = in_array($users['group_name'], ['COMMERCIALE']);
|
||||
$isCaissier = in_array($users['group_name'], ['Caissière']);
|
||||
|
||||
$builder = $this->where('amount_due', 0)
|
||||
->groupStart()
|
||||
$builder = $this->where('is_order', 0)
|
||||
->where('active', 1)
|
||||
->orWhere('is_order', 1)
|
||||
->groupEnd();
|
||||
->where('amount_due', 0);
|
||||
|
||||
if ($isCommercial) {
|
||||
$builder->where('user_id', $users['id']);
|
||||
|
||||
@ -13,7 +13,7 @@ class Company extends Model
|
||||
protected $table = 'company';
|
||||
// List all the fields that are allowed to be updated or inserted
|
||||
protected $allowedFields = [
|
||||
'company_name', 'service_charge_value', 'vat_charge_value', 'address', 'phone', 'phone2', 'NIF', 'STAT', 'country', 'message', 'currency', 'logo',
|
||||
'company_name', 'service_charge_value', 'vat_charge_value', 'address', 'phone', 'phone2', 'NIF', 'STAT', 'country', 'message', 'currency',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@ -99,22 +99,4 @@ class Groups extends Model
|
||||
->get()
|
||||
->getRowArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all groups that have a specific permission
|
||||
* @param string $permission
|
||||
* @return array
|
||||
*/
|
||||
public function getGroupsWithPermission(string $permission): array
|
||||
{
|
||||
$groups = $this->findAll();
|
||||
$result = [];
|
||||
foreach ($groups as $group) {
|
||||
$perms = @unserialize($group['permission'] ?? '');
|
||||
if (is_array($perms) && in_array($permission, $perms)) {
|
||||
$result[] = $group;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@ -16,8 +16,6 @@ class Historique extends Model
|
||||
'sku',
|
||||
'store_name',
|
||||
'description',
|
||||
'user_id',
|
||||
'user_name',
|
||||
'created_at'
|
||||
];
|
||||
protected $useTimestamps = false;
|
||||
@ -113,32 +111,6 @@ class Historique extends Model
|
||||
return $this->insert($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enregistrer une action utilisateur dans l'historique
|
||||
*/
|
||||
public function logAction($tableName, $action, $rowId, $description)
|
||||
{
|
||||
$session = session();
|
||||
$user = $session->get('user');
|
||||
|
||||
$data = [
|
||||
'table_name' => $tableName,
|
||||
'action' => $action,
|
||||
'row_id' => $rowId,
|
||||
'product_name' => null,
|
||||
'sku' => null,
|
||||
'store_name' => $user['store_name'] ?? null,
|
||||
'description' => $description,
|
||||
'user_id' => $user['id'] ?? null,
|
||||
'user_name' => isset($user['firstname'], $user['lastname'])
|
||||
? $user['firstname'] . ' ' . $user['lastname']
|
||||
: ($user['username'] ?? 'Système'),
|
||||
'created_at' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
return $this->insert($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nettoyer l'historique ancien (plus de X jours)
|
||||
*/
|
||||
@ -192,7 +164,7 @@ class Historique extends Model
|
||||
{
|
||||
$data = $this->getHistoriqueWithFilters($filters);
|
||||
|
||||
$csvData = "ID,Table,Action,ID Produit,Nom Produit,N° de série,Magasin,Description,Date/Heure\n";
|
||||
$csvData = "ID,Table,Action,ID Produit,Nom Produit,SKU,Magasin,Description,Date/Heure\n";
|
||||
|
||||
foreach ($data as $row) {
|
||||
$csvData .= '"' . $row['id'] . '",';
|
||||
|
||||
@ -24,32 +24,15 @@ class OrderItems extends Model
|
||||
return $this->where('order_id', $order_id)->findAll();
|
||||
}
|
||||
|
||||
public function getAllSoldProductToday($startDate = null, $endDate = null, $storeId = null, $userId = null) {
|
||||
$builder = $this->select('
|
||||
public function getAllSoldProductToday() {
|
||||
return $this->select('
|
||||
COUNT(orders_item.id) as total_product_sold,
|
||||
(SELECT SUM(products.qty) FROM products) as total_unsold_product
|
||||
')
|
||||
->join('orders', 'orders_item.order_id = orders.id');
|
||||
|
||||
if (!empty($startDate) || !empty($endDate) || !empty($storeId) || !empty($userId)) {
|
||||
if (!empty($startDate)) {
|
||||
$builder->where('DATE(orders.date_time) >=', $startDate);
|
||||
}
|
||||
if (!empty($endDate)) {
|
||||
$builder->where('DATE(orders.date_time) <=', $endDate);
|
||||
}
|
||||
} else {
|
||||
$builder->where('DATE(orders.date_time)', date('Y-m-d'));
|
||||
}
|
||||
|
||||
if (!empty($storeId)) {
|
||||
$builder->where('orders.store_id', $storeId);
|
||||
}
|
||||
if (!empty($userId)) {
|
||||
$builder->where('orders.user_id', $userId);
|
||||
}
|
||||
|
||||
return $builder->get()->getRow();
|
||||
->join('orders', 'orders_item.order_id = orders.id')
|
||||
->where('DATE(orders.date_time)', date('Y-m-d'))
|
||||
->get()
|
||||
->getRow();
|
||||
}
|
||||
|
||||
public function getSumOrdersItemData($order_id = null)
|
||||
|
||||
@ -124,7 +124,6 @@ class Orders extends Model
|
||||
->join('orders_item', 'orders_item.order_id = orders.id', 'left')
|
||||
->join('products', 'products.id = orders_item.product_id', 'left')
|
||||
->select("IFNULL(GROUP_CONCAT(DISTINCT products.name SEPARATOR '\\n'), '') AS product_names", false)
|
||||
->select("COUNT(DISTINCT orders_item.id) AS item_count", false)
|
||||
->groupBy('orders.id');
|
||||
|
||||
// Récupération du groupe de l'utilisateur
|
||||
@ -275,15 +274,15 @@ class Orders extends Model
|
||||
$orderItemModel->where('order_id', $id)->delete();
|
||||
|
||||
// Insert new items
|
||||
$count_product = is_array($data['product']) ? count($data['product']) : 0;
|
||||
$count_product = count($data['product']);
|
||||
for ($x = 0; $x < $count_product; $x++) {
|
||||
$items = [
|
||||
'order_id' => $id,
|
||||
'product_id' => is_array($data['product']) ? $data['product'][$x] : $data['product'],
|
||||
'rate' => is_array($data['rate_value']) ? ($data['rate_value'][$x] ?? 0) : ($data['rate_value'] ?? 0),
|
||||
'qty' => is_array($data['qty']) ? (int)($data['qty'][$x] ?? 1) : 1,
|
||||
'puissance' => is_array($data['puissance']) ? ($data['puissance'][$x] ?? '') : ($data['puissance'] ?? ''),
|
||||
'amount' => is_array($data['amount_value']) ? ($data['amount_value'][$x] ?? 0) : ($data['amount_value'] ?? 0),
|
||||
'product_id' => $data['product'][$x],
|
||||
'rate' => $data['rate_value'][$x],
|
||||
'qty' => isset($data['qty'][$x]) ? (int)$data['qty'][$x] : 1,
|
||||
'puissance' => $data['puissance'][$x],
|
||||
'amount' => $data['amount_value'][$x],
|
||||
];
|
||||
|
||||
$orderItemModel->insert($items);
|
||||
@ -388,7 +387,7 @@ class Orders extends Model
|
||||
->findAll();
|
||||
}
|
||||
|
||||
public function getPaymentModes($startDate = null, $endDate = null, $storeId = null, $userId = null)
|
||||
public function getPaymentModes()
|
||||
{
|
||||
$session = session();
|
||||
$users = $session->get('user');
|
||||
@ -465,67 +464,28 @@ class Orders extends Model
|
||||
')
|
||||
->whereIn('orders.paid_status', [1, 3]);
|
||||
|
||||
if (!empty($storeId)) {
|
||||
$baseQuery->where('orders.store_id', $storeId);
|
||||
} elseif (!$isAdmin) {
|
||||
if (!$isAdmin) {
|
||||
$baseQuery->where('orders.store_id', $users['store_id']);
|
||||
}
|
||||
|
||||
if (!empty($userId)) {
|
||||
$baseQuery->where('orders.user_id', $userId);
|
||||
}
|
||||
|
||||
if ($startDate) {
|
||||
$baseQuery->where('DATE(orders.date_time) >=', $startDate);
|
||||
}
|
||||
if ($endDate) {
|
||||
$baseQuery->where('DATE(orders.date_time) <=', $endDate);
|
||||
}
|
||||
|
||||
return $baseQuery->get()->getRowObject();
|
||||
}
|
||||
|
||||
public function getTotalOrders($startDate = null, $endDate = null, $storeId = null, $userId = null)
|
||||
public function getTotalOrders()
|
||||
{
|
||||
$builder = $this->db->table('orders')
|
||||
->select('COUNT(*) as total_orders');
|
||||
|
||||
if (!empty($storeId)) {
|
||||
$builder->where('store_id', $storeId);
|
||||
}
|
||||
if (!empty($userId)) {
|
||||
$builder->where('user_id', $userId);
|
||||
}
|
||||
if (!empty($startDate)) {
|
||||
$builder->where('DATE(date_time) >=', $startDate);
|
||||
}
|
||||
if (!empty($endDate)) {
|
||||
$builder->where('DATE(date_time) <=', $endDate);
|
||||
return $this->db->table('orders')
|
||||
->select(' COUNT(*) as total_orders')
|
||||
->get()
|
||||
->getRow();
|
||||
}
|
||||
|
||||
return $builder->get()->getRow();
|
||||
}
|
||||
|
||||
public function getTotalOrderPerStore($startDate = null, $endDate = null, $storeId = null, $userId = null)
|
||||
public function getTotalOrderPerStore()
|
||||
{
|
||||
$builder = $this->db->table('orders')
|
||||
return $this->db->table('orders')
|
||||
->select('store_id, COUNT(*) as total')
|
||||
->groupBy('store_id');
|
||||
|
||||
if (!empty($storeId)) {
|
||||
$builder->where('store_id', $storeId);
|
||||
}
|
||||
if (!empty($userId)) {
|
||||
$builder->where('user_id', $userId);
|
||||
}
|
||||
if (!empty($startDate)) {
|
||||
$builder->where('DATE(date_time) >=', $startDate);
|
||||
}
|
||||
if (!empty($endDate)) {
|
||||
$builder->where('DATE(date_time) <=', $endDate);
|
||||
}
|
||||
|
||||
return $builder->get()->getResult();
|
||||
->groupBy('store_id')
|
||||
->get()
|
||||
->getResult();
|
||||
}
|
||||
|
||||
public function getPaymentModesPercentage()
|
||||
@ -589,31 +549,35 @@ class Orders extends Model
|
||||
return $order;
|
||||
}
|
||||
|
||||
public function getTotalProductvente2(?int $id, $startDate = null, $endDate = null)
|
||||
public function getTotalProductvente2(?int $id)
|
||||
{
|
||||
$builder = $this->db->table('orders')
|
||||
if ($id != 0) {
|
||||
$order = $this->db->table('orders')
|
||||
->select('orders.id, orders.paid_status, orders.store_id, orders.date_time, brands.name, products.name as Pname, products.sku')
|
||||
->join('orders_item', 'orders.id = orders_item.order_id')
|
||||
->join('products', 'orders_item.product_id = products.id')
|
||||
->join('brands', 'brands.id = products.marque')
|
||||
->whereIn('orders.paid_status', [1, 3]);
|
||||
|
||||
if ($id != 0) {
|
||||
$builder->where('orders.store_id', $id);
|
||||
}
|
||||
if (!empty($startDate)) {
|
||||
$builder->where('DATE(orders.date_time) >=', $startDate);
|
||||
}
|
||||
if (!empty($endDate)) {
|
||||
$builder->where('DATE(orders.date_time) <=', $endDate);
|
||||
->whereIn('orders.paid_status', [1, 3]) // ← CHANGÉ ICI
|
||||
->where('orders.store_id', $id)
|
||||
->get()
|
||||
->getResult();
|
||||
} else {
|
||||
$order = $this->db->table('orders')
|
||||
->select('orders.id, orders.paid_status, orders.store_id, orders.date_time, brands.name, products.name as Pname, products.sku')
|
||||
->join('orders_item', 'orders.id = orders_item.order_id')
|
||||
->join('products', 'orders_item.product_id = products.id')
|
||||
->join('brands', 'brands.id = products.marque')
|
||||
->whereIn('orders.paid_status', [1, 3]) // ← CHANGÉ ICI
|
||||
->get()
|
||||
->getResult();
|
||||
}
|
||||
|
||||
return $builder->get()->getResult();
|
||||
return $order;
|
||||
}
|
||||
|
||||
public function getOrderVendue($storeId = null, $startDate = null, $endDate = null)
|
||||
public function getOrderVendue()
|
||||
{
|
||||
$builder = $this->db->table('products')
|
||||
$order = $this->db->table('products')
|
||||
->select('
|
||||
products.*,
|
||||
products.name as Pname,
|
||||
@ -624,25 +588,17 @@ class Orders extends Model
|
||||
ELSE orders.gross_amount
|
||||
END as totalNet,
|
||||
orders.date_time as DateTime
|
||||
', false)
|
||||
', false) // ← MODIFIÉ ICI
|
||||
->join('orders_item', 'products.id = orders_item.product_id')
|
||||
->join('orders', 'orders_item.order_id = orders.id')
|
||||
->whereIn('orders.paid_status', [1, 3]);
|
||||
->whereIn('orders.paid_status', [1, 3]) // ← ET ICI
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
if (!empty($storeId) && $storeId != 0) {
|
||||
$builder->where('orders.store_id', $storeId);
|
||||
}
|
||||
if (!empty($startDate)) {
|
||||
$builder->where('DATE(orders.date_time) >=', $startDate);
|
||||
}
|
||||
if (!empty($endDate)) {
|
||||
$builder->where('DATE(orders.date_time) <=', $endDate);
|
||||
return $order;
|
||||
}
|
||||
|
||||
return $builder->get()->getResultArray();
|
||||
}
|
||||
|
||||
public function getPerformanceByOrders($startDate = null, $endDate = null, $pvente = null, $commercialId = null)
|
||||
public function getPerformanceByOrders($startDate = null, $endDate = null, $pvente = null)
|
||||
{
|
||||
$builder = $this->db->table('orders')
|
||||
->select('orders.id as orderid, orders.net_amount, orders.date_time as datevente, orders.discount, products.price, products.sku, products.prix_vente, products.name as motoname, stores.id as store_id, users.firstname, users.lastname, users.email')
|
||||
@ -652,6 +608,7 @@ class Orders extends Model
|
||||
->join('users', 'users.id = orders.user_id')
|
||||
->whereIn('orders.paid_status', [1, 3]);
|
||||
|
||||
// ✅ AJOUT : FILTRES PAR DATE
|
||||
if (!empty($startDate) && !empty($endDate)) {
|
||||
$builder->where('DATE(orders.date_time) >=', $startDate);
|
||||
$builder->where('DATE(orders.date_time) <=', $endDate);
|
||||
@ -661,14 +618,11 @@ class Orders extends Model
|
||||
$builder->where('DATE(orders.date_time) <=', $endDate);
|
||||
}
|
||||
|
||||
// ✅ AJOUT : FILTRE PAR POINT DE VENTE
|
||||
if (!empty($pvente) && $pvente !== 'TOUS') {
|
||||
$builder->where('stores.name', $pvente);
|
||||
}
|
||||
|
||||
if (!empty($commercialId) && $commercialId !== 'TOUS') {
|
||||
$builder->where('orders.user_id', $commercialId);
|
||||
}
|
||||
|
||||
$builder->orderBy('orders.date_time', 'DESC');
|
||||
|
||||
return $builder->get()->getResultArray();
|
||||
|
||||
@ -21,7 +21,7 @@ class Products extends Model
|
||||
$isAdmin = in_array($user['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
|
||||
|
||||
$builder = $this->where('is_piece', 0)
|
||||
->whereIn('product_sold', [0, 2]);
|
||||
->where('product_sold', 0);
|
||||
|
||||
if (!$isAdmin) {
|
||||
if (empty($user['store_id']) || $user['store_id'] == 0) {
|
||||
@ -58,27 +58,11 @@ class Products extends Model
|
||||
|
||||
return $builder->join('brands', 'brands.id = products.marque')
|
||||
->orderBy('products.id', 'DESC')
|
||||
->select('brands.name as brand_name, products.store_id as store_id, products.*')
|
||||
->select('brands.name as brand_name,COUNT( products.id) as total_product, products.store_id as store_id,products.*')
|
||||
->groupBy('store_id')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
public function getStockByBrand(int $id = 0)
|
||||
{
|
||||
$builder = $this->db->table('products')
|
||||
->select('brands.name as brand_name, products.store_id, COUNT(*) as total_product')
|
||||
->join('brands', 'brands.id = products.marque')
|
||||
->where('products.is_piece', 0)
|
||||
->where('products.product_sold', 0);
|
||||
|
||||
if ($id > 0) {
|
||||
$builder->where('products.store_id', $id);
|
||||
}
|
||||
|
||||
return $builder->groupBy('brands.name, products.store_id')
|
||||
->orderBy('total_product', 'DESC')
|
||||
->get()->getResultArray();
|
||||
}
|
||||
|
||||
public function getProductData3(int $id)
|
||||
{
|
||||
if ($id == 0) {
|
||||
@ -91,7 +75,7 @@ class Products extends Model
|
||||
public function getProductDataStore(int $store_id, bool $excludeAvance = true, int $currentProductId = null)
|
||||
{
|
||||
$builder = $this->where('is_piece', 0)
|
||||
->whereIn('product_sold', [0, 2])
|
||||
->where('product_sold', 0)
|
||||
->where('availability', 1)
|
||||
->where('store_id', $store_id);
|
||||
|
||||
@ -108,12 +92,11 @@ class Products extends Model
|
||||
$builder->where("id NOT IN ($subQueryAvances)", null, false);
|
||||
}
|
||||
|
||||
// ✅ LISTE : Exclure uniquement les produits dont la commande est LIVRÉE (paid_status = 3)
|
||||
// Les produits commandés mais non livrés restent visibles dans les produits disponibles
|
||||
// ✅ LISTE : Exclure TOUS les produits ayant une commande (statuts 1, 2, 3)
|
||||
$subQueryOrders = $db->table('orders_item')
|
||||
->select('orders_item.product_id')
|
||||
->join('orders', 'orders.id = orders_item.order_id')
|
||||
->where('orders.paid_status', 3)
|
||||
->whereIn('orders.paid_status', [1, 2, 3]) // ✅ Disparaît de la liste dès qu'il y a une commande
|
||||
->getCompiledSelect();
|
||||
|
||||
$builder->where("id NOT IN ($subQueryOrders)", null, false);
|
||||
|
||||
@ -16,9 +16,10 @@ class Remise extends Model
|
||||
$session = session();
|
||||
$users = $session->get('user');
|
||||
|
||||
// ✅ SUPERADMIN VOIT TOUTES LES DEMANDES (TOUS STATUTS)
|
||||
// ✅ SUPERADMIN VOIT TOUTES LES DEMANDES "EN ATTENTE" (POUR VALIDATION)
|
||||
if ($users["group_name"] === "SuperAdmin") {
|
||||
return $this->orderBy('date_demande', 'DESC')
|
||||
return $this->where('demande_status', 'En attente')
|
||||
->orderBy('date_demande', 'DESC')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
|
||||
@ -39,28 +39,13 @@ class Reports extends Model
|
||||
* @param mixed $year
|
||||
* @return array<array>
|
||||
*/
|
||||
public function getOrderData($year, $startDate = null, $endDate = null, $storeId = null, $userId = null)
|
||||
public function getOrderData($year)
|
||||
{
|
||||
if ($year) {
|
||||
$months = $this->months();
|
||||
|
||||
// Fetch orders with paid_status = 1 or 3
|
||||
$builder = $this->whereIn('paid_status', [1, 3]);
|
||||
|
||||
if (!empty($storeId)) {
|
||||
$builder->where('store_id', $storeId);
|
||||
}
|
||||
if (!empty($userId)) {
|
||||
$builder->where('user_id', $userId);
|
||||
}
|
||||
if (!empty($startDate)) {
|
||||
$builder->where('DATE(date_time) >=', $startDate);
|
||||
}
|
||||
if (!empty($endDate)) {
|
||||
$builder->where('DATE(date_time) <=', $endDate);
|
||||
}
|
||||
|
||||
$result = $builder->findAll();
|
||||
$result = $this->whereIn('paid_status', [1, 3])->findAll();
|
||||
|
||||
$final_data = [];
|
||||
|
||||
@ -71,10 +56,11 @@ class Reports extends Model
|
||||
foreach ($result as $v) {
|
||||
$month_year = date('Y-m', strtotime($v['date_time']));
|
||||
if ($get_mon_year == $month_year) {
|
||||
// Modifier le montant selon votre logique
|
||||
if (!empty($v['discount']) && $v['discount'] > 0) {
|
||||
$v['amount_to_display'] = $v['discount'];
|
||||
$v['amount_to_display'] = $v['discount']; // Utiliser le rabais
|
||||
} else {
|
||||
$v['amount_to_display'] = $v['gross_amount'];
|
||||
$v['amount_to_display'] = $v['gross_amount']; // Utiliser gross_amount
|
||||
}
|
||||
$final_data[$get_mon_year][] = $v;
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ class Securite extends Model
|
||||
*/
|
||||
protected $table = 'securite';
|
||||
protected $primaryKey = 'id'; // Primary key column
|
||||
protected $allowedFields = ['product_id', 'bill_no', 'store_id', 'status', 'date', 'active'];
|
||||
protected $allowedFields = ['product_id', 'status', 'date', 'active'];
|
||||
|
||||
|
||||
|
||||
|
||||
@ -165,24 +165,25 @@ class SortieCaisse extends Model
|
||||
/**
|
||||
* ✅ MODIFICATION : DAF, Direction, SuperAdmin voient TOUS les totaux
|
||||
*/
|
||||
public function getTotalSortieCaisse($startDate = null, $endDate = null) {
|
||||
public function getTotalSortieCaisse() {
|
||||
$session = session();
|
||||
$users = $session->get('user');
|
||||
|
||||
// ✅ DAF, Direction, SuperAdmin : Voir TOUS les stores
|
||||
$isAdmin = in_array($users['group_name'], ['Direction', 'DAF', 'SuperAdmin']);
|
||||
|
||||
if ($isAdmin) {
|
||||
try {
|
||||
$builder = $this->select('
|
||||
return $this->select('
|
||||
SUM(CASE WHEN mode_paiement = "En espèce" AND statut = "Payé" THEN montant_retire ELSE 0 END) AS total_espece,
|
||||
SUM(CASE WHEN mode_paiement = "MVOLA" AND statut = "Payé" THEN montant_retire ELSE 0 END) AS total_mvola,
|
||||
SUM(CASE WHEN mode_paiement = "Virement Bancaire" AND statut = "Payé" THEN montant_retire ELSE 0 END) AS total_virement,
|
||||
SUM(CASE WHEN statut = "Payé" THEN montant_retire ELSE 0 END) AS mr
|
||||
')
|
||||
->where('statut', 'Payé');
|
||||
if ($startDate) { $builder->where('DATE(created_at) >=', $startDate); }
|
||||
if ($endDate) { $builder->where('DATE(created_at) <=', $endDate); }
|
||||
return $builder->get()->getRowObject();
|
||||
// ✅ CHANGEMENT : Uniquement statut = "Payé" (plus "Valider")
|
||||
->where('statut', 'Payé')
|
||||
->get()
|
||||
->getRowObject();
|
||||
} catch (\Exception $e) {
|
||||
log_message('error', 'Erreur getTotalSortieCaisse (Admin) : ' . $e->getMessage());
|
||||
return (object)[
|
||||
@ -193,18 +194,19 @@ class SortieCaisse extends Model
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// ✅ CAISSIÈRE : Uniquement son store ET statut "Payé"
|
||||
try {
|
||||
$builder = $this->select('
|
||||
return $this->select('
|
||||
SUM(CASE WHEN mode_paiement = "En espèce" AND statut = "Payé" THEN montant_retire ELSE 0 END) AS total_espece,
|
||||
SUM(CASE WHEN mode_paiement = "MVOLA" AND statut = "Payé" THEN montant_retire ELSE 0 END) AS total_mvola,
|
||||
SUM(CASE WHEN mode_paiement = "Virement Bancaire" AND statut = "Payé" THEN montant_retire ELSE 0 END) AS total_virement,
|
||||
SUM(CASE WHEN statut = "Payé" THEN montant_retire ELSE 0 END) AS mr
|
||||
')
|
||||
->where('store_id', $users['store_id'])
|
||||
->where('statut', 'Payé');
|
||||
if ($startDate) { $builder->where('DATE(created_at) >=', $startDate); }
|
||||
if ($endDate) { $builder->where('DATE(created_at) <=', $endDate); }
|
||||
return $builder->get()->getRowObject();
|
||||
// ✅ CHANGEMENT : Uniquement statut = "Payé" (plus "Valider")
|
||||
->where('statut', 'Payé')
|
||||
->get()
|
||||
->getRowObject();
|
||||
} catch (\Exception $e) {
|
||||
log_message('error', 'Erreur getTotalSortieCaisse (Store) : ' . $e->getMessage());
|
||||
return (object)[
|
||||
|
||||
@ -1,178 +0,0 @@
|
||||
<meta charset="UTF-8">
|
||||
<div class="content-wrapper">
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
Historique des <small>Actions</small>
|
||||
</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="<?= base_url('/') ?>"><i class="fa fa-dashboard"></i> Accueil</a></li>
|
||||
<li class="active">Historique des Actions</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section class="content">
|
||||
<div id="messages"></div>
|
||||
|
||||
<!-- Filtres -->
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title"><i class="fa fa-filter"></i> Filtres</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<label>Date de debut</label>
|
||||
<input type="date" id="filterDateFrom" class="form-control" value="<?= date('Y-m-d') ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label>Date de fin</label>
|
||||
<input type="date" id="filterDateTo" class="form-control" value="<?= date('Y-m-d') ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label>Action</label>
|
||||
<select id="filterAction" class="form-control">
|
||||
<option value="">Toutes</option>
|
||||
<option value="CREATE">Creation</option>
|
||||
<option value="UPDATE">Modification</option>
|
||||
<option value="DELETE">Suppression</option>
|
||||
<option value="PAYMENT">Paiement</option>
|
||||
<option value="VALIDATE">Validation</option>
|
||||
<option value="REFUSE">Refus</option>
|
||||
<option value="DELIVERY">Livraison</option>
|
||||
<option value="ASSIGN_STORE">Assignation</option>
|
||||
<option value="ENTRER">Entree</option>
|
||||
<option value="SORTIE">Sortie</option>
|
||||
<option value="LOGIN">Connexion</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label>Magasin</label>
|
||||
<select id="filterStore" class="form-control">
|
||||
<option value="">Tous</option>
|
||||
<?php if (isset($stores) && is_array($stores)): ?>
|
||||
<?php foreach ($stores as $store): ?>
|
||||
<option value="<?= $store['name'] ?>"><?= $store['name'] ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label> </label>
|
||||
<div>
|
||||
<button type="button" class="btn btn-primary btn-block" id="btnFilter">
|
||||
<i class="fa fa-search"></i> Filtrer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label> </label>
|
||||
<div>
|
||||
<button type="button" class="btn btn-warning btn-block" id="btnReset">
|
||||
<i class="fa fa-refresh"></i> Reinitialiser
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tableau -->
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<div class="pull-right">
|
||||
<button type="button" class="btn btn-success" id="btnExport">
|
||||
<i class="fa fa-download"></i> Exporter CSV
|
||||
</button>
|
||||
</div>
|
||||
<h3 class="box-title"><i class="fa fa-history"></i> Toutes les actions</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<table id="actionLogTable" class="table table-bordered table-striped" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Utilisateur</th>
|
||||
<th>Action</th>
|
||||
<th>Module</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#mainActionLogNav").addClass('active');
|
||||
|
||||
$.extend(true, $.fn.dataTable.defaults, {
|
||||
language: {
|
||||
sProcessing: "Traitement en cours...",
|
||||
sSearch: "Rechercher :",
|
||||
sLengthMenu: "Afficher _MENU_ elements",
|
||||
sInfo: "Affichage de l'element _START_ a _END_ sur _TOTAL_ elements",
|
||||
sInfoEmpty: "Affichage de l'element 0 a 0 sur 0 element",
|
||||
sInfoFiltered: "(filtre de _MAX_ elements au total)",
|
||||
sLoadingRecords: "Chargement en cours...",
|
||||
sZeroRecords: "Aucun element a afficher",
|
||||
sEmptyTable: "Aucune donnee disponible",
|
||||
oPaginate: {
|
||||
sFirst: "Premier",
|
||||
sPrevious: "Precedent",
|
||||
sNext: "Suivant",
|
||||
sLast: "Dernier"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var base_url = '<?= base_url() ?>';
|
||||
|
||||
function loadTable() {
|
||||
if ($.fn.DataTable.isDataTable('#actionLogTable')) {
|
||||
$('#actionLogTable').DataTable().destroy();
|
||||
}
|
||||
|
||||
$('#actionLogTable').DataTable({
|
||||
ajax: {
|
||||
url: base_url + '/action-log/fetchData',
|
||||
type: 'GET',
|
||||
data: function(d) {
|
||||
d.date_from = $('#filterDateFrom').val();
|
||||
d.date_to = $('#filterDateTo').val();
|
||||
d.action = $('#filterAction').val();
|
||||
d.store_name = $('#filterStore').val();
|
||||
}
|
||||
},
|
||||
order: [[0, 'desc']],
|
||||
pageLength: 25
|
||||
});
|
||||
}
|
||||
|
||||
loadTable();
|
||||
|
||||
$('#btnFilter').on('click', function() {
|
||||
loadTable();
|
||||
});
|
||||
|
||||
$('#btnReset').on('click', function() {
|
||||
$('#filterDateFrom').val('<?= date('Y-m-d') ?>');
|
||||
$('#filterDateTo').val('<?= date('Y-m-d') ?>');
|
||||
$('#filterAction').val('');
|
||||
$('#filterStore').val('');
|
||||
loadTable();
|
||||
});
|
||||
|
||||
$('#btnExport').on('click', function() {
|
||||
var params = '?date_from=' + $('#filterDateFrom').val()
|
||||
+ '&date_to=' + $('#filterDateTo').val()
|
||||
+ '&action=' + $('#filterAction').val()
|
||||
+ '&store_name=' + $('#filterStore').val();
|
||||
window.location.href = base_url + '/action-log/export' + params;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@ -42,16 +42,12 @@ $isCaissier = isset($users['group_name']) && in_array($users['group_name'], ['Ca
|
||||
|
||||
<div class="col-md-3">
|
||||
<button id="avance_no_order" class="btn btn-info w-100 rounded-pill shadow-sm py-2">
|
||||
<i class="fa fa-hourglass-half me-2"></i>
|
||||
<span class="badge badge-light" id="incomplete-count">0</span>
|
||||
Avances Incomplètes
|
||||
<i class="fa fa-hourglass-half me-2"></i> Avances Incomplètes
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<button id="avance_order" class="btn btn-success w-100 rounded-pill shadow-sm py-2">
|
||||
<i class="fa fa-check-circle me-2"></i>
|
||||
<span class="badge badge-light" id="complete-count">0</span>
|
||||
Avances Complètes
|
||||
<i class="fa fa-check-circle me-2"></i> Avances Complètes
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
@ -86,7 +82,6 @@ $isCaissier = isset($users['group_name']) && in_array($users['group_name'], ['Ca
|
||||
<th>Téléphone</th>
|
||||
<th>Adresse</th>
|
||||
<th>Produit</th>
|
||||
<th>N° Série</th>
|
||||
<th>Prix</th>
|
||||
<th>Avance</th>
|
||||
<th>Reste à payer</th>
|
||||
@ -101,7 +96,6 @@ $isCaissier = isset($users['group_name']) && in_array($users['group_name'], ['Ca
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Produit</th>
|
||||
<th>N° Série</th>
|
||||
<th>Avance</th>
|
||||
<th>Reste à payer</th>
|
||||
<th>Date</th>
|
||||
@ -506,38 +500,6 @@ $(document).ready(function() {
|
||||
}
|
||||
}
|
||||
|
||||
// Compteurs avances
|
||||
function loadAvanceCounts() {
|
||||
$.ajax({
|
||||
url: base_url + 'avances/fetchAvanceData',
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
var count = response.data ? response.data.length : 0;
|
||||
$('#incomplete-count').text(count);
|
||||
if (count > 0) {
|
||||
$('#incomplete-count').removeClass('badge-light').addClass('badge-danger');
|
||||
} else {
|
||||
$('#incomplete-count').removeClass('badge-danger').addClass('badge-light');
|
||||
}
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
url: base_url + 'avances/fetchAvanceBecameOrder',
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
var count = response.data ? response.data.length : 0;
|
||||
$('#complete-count').text(count);
|
||||
if (count > 0) {
|
||||
$('#complete-count').removeClass('badge-light').addClass('badge-success');
|
||||
} else {
|
||||
$('#complete-count').removeClass('badge-success').addClass('badge-light');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Variables de rôles
|
||||
var isCaissier = <?php echo json_encode($isCaissier ?? false); ?>;
|
||||
var isCommerciale = <?php echo json_encode($isCommerciale ?? false); ?>;
|
||||
@ -554,7 +516,6 @@ $(document).ready(function() {
|
||||
{ title: "Téléphone" },
|
||||
{ title: "Adresse" },
|
||||
{ title: "Produit" },
|
||||
{ title: "N° Série" },
|
||||
{
|
||||
title: "Prix",
|
||||
render: function(data, type, row) {
|
||||
@ -581,43 +542,14 @@ $(document).ready(function() {
|
||||
|
||||
var manageTable = initAvanceTable(base_url + 'avances/fetchAvanceData', adminColumns);
|
||||
|
||||
// Charger les compteurs
|
||||
loadAvanceCounts();
|
||||
setInterval(loadAvanceCounts, 30000);
|
||||
|
||||
$('#avance_no_order').on('click', function() {
|
||||
$('#table-title').text('Avances Incomplètes');
|
||||
manageTable = initAvanceTable(base_url + 'avances/fetchAvanceData', adminColumns);
|
||||
});
|
||||
|
||||
var adminCompletedColumns = [
|
||||
{ title: "Client" },
|
||||
{ title: "Téléphone" },
|
||||
{ title: "Adresse" },
|
||||
{ title: "Produit" },
|
||||
{ title: "N° Série" },
|
||||
{
|
||||
title: "Prix",
|
||||
render: function(data, type, row) {
|
||||
return type === 'display' ? formatNumber(data) : data;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Avance",
|
||||
render: function(data, type, row) {
|
||||
return type === 'display' ? formatNumber(data) : data;
|
||||
}
|
||||
},
|
||||
{ title: "Statut" },
|
||||
{ title: "Date" }
|
||||
<?php if (in_array('updateAvance', $user_permission) || in_array('deleteAvance', $user_permission)): ?>
|
||||
,{ title: "Action", orderable: false, searchable: false }
|
||||
<?php endif; ?>
|
||||
];
|
||||
|
||||
$('#avance_order').on('click', function() {
|
||||
$('#table-title').text('Avances Complètes');
|
||||
manageTable = initAvanceTable(base_url + 'avances/fetchAvanceBecameOrder', adminCompletedColumns);
|
||||
manageTable = initAvanceTable(base_url + 'avances/fetchAvanceBecameOrder', adminColumns);
|
||||
});
|
||||
|
||||
$('#avance_expired').on('click', function() {
|
||||
@ -631,7 +563,6 @@ $(document).ready(function() {
|
||||
var userColumns = [
|
||||
{ title: "#" },
|
||||
{ title: "Produit" },
|
||||
{ title: "N° Série" },
|
||||
{
|
||||
title: "Avance",
|
||||
render: function(data, type, row) {
|
||||
@ -662,11 +593,10 @@ $(document).ready(function() {
|
||||
$('#avanceTable').DataTable().destroy();
|
||||
}
|
||||
|
||||
// Reconstruire les headers (format caissière/commercial)
|
||||
// ✅ Reconstruire les headers (format caissière/commercial)
|
||||
rebuildTableHeaders([
|
||||
'#',
|
||||
'Produit',
|
||||
'N° Série',
|
||||
'Avance',
|
||||
'Reste à payer',
|
||||
'Date',
|
||||
@ -699,32 +629,19 @@ $('#avance_order').on('click', function() {
|
||||
rebuildTableHeaders([
|
||||
'#',
|
||||
'Produit',
|
||||
'N° Série',
|
||||
'Avance',
|
||||
'Statut',
|
||||
'Reste à payer',
|
||||
'Date',
|
||||
'Action'
|
||||
]);
|
||||
|
||||
var completedUserColumns = [
|
||||
{ title: "#" },
|
||||
{ title: "Produit" },
|
||||
{ title: "N° Série" },
|
||||
{ title: "Avance" },
|
||||
{ title: "Statut" },
|
||||
{ title: "Date" }
|
||||
<?php if (in_array('updateAvance', $user_permission) || in_array('deleteAvance', $user_permission)): ?>
|
||||
,{ title: "Action", orderable: false, searchable: false }
|
||||
<?php endif; ?>
|
||||
];
|
||||
|
||||
manageTable = $('#avanceTable').DataTable({
|
||||
ajax: {
|
||||
url: base_url + 'avances/fetchAvanceBecameOrder',
|
||||
type: 'GET',
|
||||
dataSrc: 'data'
|
||||
},
|
||||
columns: completedUserColumns,
|
||||
columns: userColumns,
|
||||
language: datatableLangFr
|
||||
});
|
||||
|
||||
@ -743,7 +660,6 @@ $('#avance_expired').on('click', function() {
|
||||
rebuildTableHeaders([
|
||||
'#',
|
||||
'Produit',
|
||||
'N° Série',
|
||||
'Avance',
|
||||
'Reste à payer',
|
||||
'Date',
|
||||
@ -763,10 +679,8 @@ $('#avance_expired').on('click', function() {
|
||||
console.log('✅ DataTable Expirées initialisée');
|
||||
});
|
||||
|
||||
// Charger les compteurs d'avances
|
||||
// Charger le compteur d'avances en attente
|
||||
loadPendingCount();
|
||||
loadAvanceCounts();
|
||||
setInterval(loadAvanceCounts, 30000);
|
||||
setInterval(loadPendingCount, 30000);
|
||||
|
||||
console.log('✅ Module caissière initialisé');
|
||||
@ -1633,17 +1547,18 @@ window.validateAvanceFunc = function(avance_id) {
|
||||
};
|
||||
|
||||
// =====================================================
|
||||
// CHARGER COMPTEURS AVANCES
|
||||
// 🔥 CHARGER COMPTEUR AVANCES EN ATTENTE
|
||||
// =====================================================
|
||||
|
||||
function loadPendingCount() {
|
||||
$.ajax({
|
||||
url: base_url + 'avances/fetchPendingValidation',
|
||||
type: 'POST',
|
||||
type: 'POST', // ✅ CORRECTION
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
var count = response.data ? response.data.length : 0;
|
||||
$('#pending-count').text(count);
|
||||
|
||||
if (count > 0) {
|
||||
$('#pending-count').removeClass('badge-light').addClass('badge-danger');
|
||||
$('#avance_pending').addClass('btn-pulse');
|
||||
@ -1651,12 +1566,13 @@ function loadPendingCount() {
|
||||
$('#pending-count').removeClass('badge-danger').addClass('badge-light');
|
||||
$('#avance_pending').removeClass('btn-pulse');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
console.error('Erreur chargement compteur avances en attente');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// loadAvanceCounts defini plus haut
|
||||
|
||||
// =====================================================
|
||||
// 🔥 TRAITER AVANCES EXPIRÉES (ADMIN)
|
||||
// =====================================================
|
||||
|
||||
@ -27,7 +27,6 @@
|
||||
<th>Prix</th>
|
||||
<th>Puissances</th>
|
||||
<th>N° Moteur</th>
|
||||
<th>Disponibilité</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -73,15 +72,10 @@ $.extend(true, $.fn.dataTable.defaults, {
|
||||
'ajax': `<?= base_url('ventes/fetchProductVente') ?>/${id}`,
|
||||
'order': [],
|
||||
'columnDefs': [{
|
||||
targets: 7,
|
||||
targets: 6,
|
||||
className: 'text-right'
|
||||
}
|
||||
],
|
||||
'createdRow': function(row, data, dataIndex) {
|
||||
if (data[6] && data[6].indexOf('En attente de livraison') !== -1) {
|
||||
$(row).css({'background-color': '#fff3cd', 'opacity': '0.85'});
|
||||
}
|
||||
}
|
||||
} // Column index 3 corresponds to "Prix"
|
||||
]
|
||||
});
|
||||
})
|
||||
</script>
|
||||
@ -34,7 +34,7 @@
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Gérer les informations sur l'entreprise</h3>
|
||||
</div>
|
||||
<form role="form" action="<?php base_url('company/update') ?>" method="post" enctype="multipart/form-data">
|
||||
<form role="form" action="<?php base_url('company/update') ?>" method="post">
|
||||
<div class="box-body">
|
||||
|
||||
<!-- Validation errors -->
|
||||
@ -48,19 +48,6 @@
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Logo de l'entreprise</label>
|
||||
<div style="margin-bottom: 10px;">
|
||||
<?php if (!empty($company_data['logo'])): ?>
|
||||
<img src="<?= base_url($company_data['logo']) ?>?v=<?= time() ?>" alt="Logo" style="max-height: 80px; border: 1px solid #ddd; padding: 5px; border-radius: 4px;">
|
||||
<?php else: ?>
|
||||
<img src="<?= base_url('assets/images/company_logo.jpg') ?>?v=<?= time() ?>" alt="Logo par defaut" style="max-height: 80px; border: 1px solid #ddd; padding: 5px; border-radius: 4px; opacity: 0.4;">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<input type="file" name="logo" accept="image/*" class="form-control" style="line-height: normal; padding: 6px 12px; height: auto;">
|
||||
<p class="help-block">Formats acceptes : JPG, PNG, GIF. Laissez vide pour garder le logo actuel.</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="company_name">Nom de l'entreprise</label>
|
||||
<input type="text" class="form-control" id="company_name" name="company_name" placeholder="Nom de l'entreprise" value="<?php echo $company_data['company_name'] ?>" autocomplete="off">
|
||||
|
||||
@ -311,13 +311,6 @@
|
||||
<h3 class="box-title">
|
||||
<i class="fa fa-calculator"></i> Résumé de Trésorerie
|
||||
</h3>
|
||||
<div class="pull-right" style="display: flex; align-items: center; gap: 8px;">
|
||||
<input type="date" id="tresoDateFrom" class="form-control input-sm" value="<?= date('Y-m-d') ?>" style="width: 140px; display: inline-block;">
|
||||
<span>au</span>
|
||||
<input type="date" id="tresoDateTo" class="form-control input-sm" value="<?= date('Y-m-d') ?>" style="width: 140px; display: inline-block;">
|
||||
<button type="button" class="btn btn-primary btn-sm" id="btnFilterTreso"><i class="fa fa-search"></i> Filtrer</button>
|
||||
<button type="button" class="btn btn-warning btn-sm" id="btnResetTreso"><i class="fa fa-refresh"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
@ -327,7 +320,7 @@
|
||||
<div class="col-sm-3 col-xs-12">
|
||||
<div class="amount-block brut">
|
||||
<span class="amount-label" style="color: #388e3c;">💰 Total Brut</span>
|
||||
<div class="amount-header" style="color: #2e7d32;" id="treso-brut">
|
||||
<div class="amount-header" style="color: #2e7d32;">
|
||||
<?php echo number_format($total_brut, 0, '.', ' '); ?> Ar
|
||||
</div>
|
||||
<span class="amount-sublabel">Orders + Avances</span>
|
||||
@ -343,7 +336,7 @@
|
||||
<div class="col-sm-3 col-xs-12">
|
||||
<div class="amount-block sorties">
|
||||
<span class="amount-label" style="color: #c62828;">💸 Décaissements</span>
|
||||
<div class="amount-header" style="color: #d32f2f;" id="treso-sorties">
|
||||
<div class="amount-header" style="color: #d32f2f;">
|
||||
<?php echo number_format($total_sorties, 0, '.', ' '); ?> Ar
|
||||
</div>
|
||||
<span class="amount-sublabel">Espèce + MVOLA + Virement</span>
|
||||
@ -359,7 +352,7 @@
|
||||
<div class="col-sm-4 col-xs-12">
|
||||
<div class="amount-block net">
|
||||
<span class="amount-label" style="color: #1565c0;">✅ Solde Net</span>
|
||||
<div class="amount-header" style="color: #1976d2; font-size: 36px;" id="treso-net">
|
||||
<div class="amount-header" style="color: #1976d2; font-size: 36px;">
|
||||
<?php echo number_format($total_caisse, 0, '.', ' '); ?> Ar
|
||||
</div>
|
||||
<span class="amount-sublabel">Disponible en caisse</span>
|
||||
@ -378,10 +371,10 @@
|
||||
<div class="payment-icon espece">
|
||||
<i class="fa fa-money"></i>
|
||||
</div>
|
||||
<div class="payment-amount" id="treso-espece">
|
||||
<div class="payment-amount">
|
||||
<?php echo number_format($total_espece_caisse, 0, '.', ' '); ?> Ar
|
||||
</div>
|
||||
<div class="payment-label">Espece Disponible</div>
|
||||
<div class="payment-label">💵 Espèce Disponible</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -391,10 +384,10 @@
|
||||
<div class="payment-icon mvola">
|
||||
<i class="fa fa-mobile"></i>
|
||||
</div>
|
||||
<div class="payment-amount" id="treso-mvola">
|
||||
<div class="payment-amount">
|
||||
<?php echo number_format($total_mvola_caisse, 0, '.', ' '); ?> Ar
|
||||
</div>
|
||||
<div class="payment-label">MVOLA Disponible</div>
|
||||
<div class="payment-label">📱 MVOLA Disponible</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -404,10 +397,10 @@
|
||||
<div class="payment-icon banque">
|
||||
<i class="fa fa-bank"></i>
|
||||
</div>
|
||||
<div class="payment-amount" id="treso-banque">
|
||||
<div class="payment-amount">
|
||||
<?php echo number_format($total_vb_caisse, 0, '.', ' '); ?> Ar
|
||||
</div>
|
||||
<div class="payment-label">Banque Disponible</div>
|
||||
<div class="payment-label">🏦 Banque Disponible</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -415,48 +408,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var baseUrl = '<?= base_url() ?>';
|
||||
|
||||
function loadTresorerie() {
|
||||
var startDate = $('#tresoDateFrom').val();
|
||||
var endDate = $('#tresoDateTo').val();
|
||||
|
||||
$.ajax({
|
||||
url: baseUrl + '/dashboard/getTresorerieData',
|
||||
type: 'GET',
|
||||
data: { start_date: startDate, end_date: endDate },
|
||||
success: function(data) {
|
||||
$('#treso-brut').text(data.total_brut + ' Ar');
|
||||
$('#treso-sorties').text(data.total_sorties + ' Ar');
|
||||
$('#treso-net').text(data.total_net + ' Ar');
|
||||
$('#treso-espece').text(data.espece + ' Ar');
|
||||
$('#treso-mvola').text(data.mvola + ' Ar');
|
||||
$('#treso-banque').text(data.banque + ' Ar');
|
||||
$('#avance-mvola').text(data.avance_mvola + ' Ar');
|
||||
$('#avance-espece').text(data.avance_espece + ' Ar');
|
||||
$('#avance-banque').text(data.avance_banque + ' Ar');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Charger par défaut avec la date d'aujourd'hui
|
||||
loadTresorerie();
|
||||
|
||||
$('#btnFilterTreso').on('click', function() {
|
||||
loadTresorerie();
|
||||
});
|
||||
|
||||
$('#btnResetTreso').on('click', function() {
|
||||
$('#tresoDateFrom').val('<?= date('Y-m-d') ?>');
|
||||
$('#tresoDateTo').val('<?= date('Y-m-d') ?>');
|
||||
loadTresorerie();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Détail des avances par mode de paiement -->
|
||||
<div class="container-fluid row" style="margin-top: 10px; margin-bottom: 20px;">
|
||||
<div class="col-lg-12">
|
||||
@ -468,19 +419,19 @@ $(document).ready(function() {
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<div class="description-block">
|
||||
<h5 class="description-header" id="avance-mvola"><?php echo number_format($total_avances_mvola, 0, '.', ' '); ?> Ar</h5>
|
||||
<h5 class="description-header"><?php echo number_format($total_avances_mvola, 0, '.', ' '); ?> Ar</h5>
|
||||
<span class="description-text">MVOLA</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="description-block">
|
||||
<h5 class="description-header" id="avance-espece"><?php echo number_format($total_avances_espece, 0, '.', ' '); ?> Ar</h5>
|
||||
<span class="description-text">ESPECE</span>
|
||||
<h5 class="description-header"><?php echo number_format($total_avances_espece, 0, '.', ' '); ?> Ar</h5>
|
||||
<span class="description-text">ESPÈCE</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="description-block">
|
||||
<h5 class="description-header" id="avance-banque"><?php echo number_format($total_avances_virement, 0, '.', ' '); ?> Ar</h5>
|
||||
<h5 class="description-header"><?php echo number_format($total_avances_virement, 0, '.', ' '); ?> Ar</h5>
|
||||
<span class="description-text">BANQUE</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -149,27 +149,28 @@
|
||||
<tr>
|
||||
<tr>
|
||||
<td>Recouvrement</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="viewRecouvrement" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="createRecouvrement" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="updateRecouvrement" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="viewRecouvrement" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="deleteRecouvrement" class="minimal"></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Décaissement</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="viewSortieCaisse" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="createSortieCaisse" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="updateSortieCaisse" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="viewSortieCaisse" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="deleteSortieCaisse" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="validateSortieCaisse" class="minimal"></td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Remise</td>
|
||||
<td>-</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="validateRemise" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="viewRemise" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="validateRemise" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="refusedRemise" class="minimal"></td>
|
||||
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Validation commande</td>
|
||||
@ -180,11 +181,11 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Securité</td>
|
||||
<td> - </td>
|
||||
<td> <input type="checkbox" name="permission[]" id="permission" value="viewSecurite" class="minimal"> </td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="createSecurite" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="updateSecurite" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="viewSecurite" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="deleteSecurite" class="minimal"></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rapports</td>
|
||||
@ -196,11 +197,11 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Avances</td>
|
||||
<td> - </td>
|
||||
<td> <input type="checkbox" name="permission[]" id="permission" value="viewAvance" class="minimal"> </td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="createAvance" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="updateAvance" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="viewAvance" class="minimal"></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" value="deleteAvance" class="minimal"></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Entreprise</td>
|
||||
|
||||
@ -75,7 +75,6 @@
|
||||
<th>Voir</th>
|
||||
<th>Supprimer</th>
|
||||
<th>Assigner</th>
|
||||
<th>Notification</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -97,7 +96,6 @@
|
||||
</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Utilisateurs</td>
|
||||
@ -142,7 +140,6 @@
|
||||
}
|
||||
}
|
||||
?>></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rôle</td>
|
||||
@ -179,7 +176,6 @@
|
||||
}
|
||||
?>></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Marques</td>
|
||||
@ -208,7 +204,6 @@
|
||||
}
|
||||
} ?>></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Categories</td>
|
||||
@ -241,7 +236,6 @@
|
||||
}
|
||||
} ?>></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Point de ventes</td>
|
||||
@ -275,7 +269,6 @@
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
|
||||
<td>Mécanicien</td>
|
||||
@ -312,7 +305,6 @@
|
||||
} ?>>
|
||||
</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Attributs</td>
|
||||
@ -345,7 +337,6 @@
|
||||
}
|
||||
} ?>></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Produits</td>
|
||||
@ -377,12 +368,6 @@
|
||||
}
|
||||
} ?>></td>
|
||||
<td>-</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="notifProduit"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('notifProduit', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Commandes</td>
|
||||
@ -411,15 +396,15 @@
|
||||
}
|
||||
} ?>></td>
|
||||
<td>-</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="notifCommande"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('notifCommande', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Recouvrement</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="viewRecouvrement"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('viewRecouvrement', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="createRecouvrement"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('createRecouvrement', $serialize_permission)) {
|
||||
@ -432,12 +417,6 @@
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="viewRecouvrement"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('viewRecouvrement', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="deleteRecouvrement"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('deleteRecouvrement', $serialize_permission)) {
|
||||
@ -445,16 +424,16 @@
|
||||
}
|
||||
} ?>></td>
|
||||
<td>-</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="notifRecouvrement"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('notifRecouvrement', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Sortie caisse</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="viewSortieCaisse"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('viewSortieCaisse', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="createSortieCaisse"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('createSortieCaisse', $serialize_permission)) {
|
||||
@ -467,12 +446,6 @@
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="viewSortieCaisse"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('viewSortieCaisse', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="deleteSortieCaisse"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('deleteSortieCaisse', $serialize_permission)) {
|
||||
@ -485,12 +458,6 @@
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="notifSortieCaisse"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('notifSortieCaisse', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Autres encaissements</td>
|
||||
@ -517,40 +484,25 @@
|
||||
if (in_array('deleteEncaissement', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td>-</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="notifEncaissement"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('notifEncaissement', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
} ?>>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Remise</td>
|
||||
<td>-</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="validateRemise"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('validateRemise', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="viewRemise"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('viewRemise', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="refusedRemise"
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="validateRemise"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('refusedRemise', $serialize_permission)) {
|
||||
if (in_array('validateRemise', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td>-</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="notifRemise"
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="refusedRemise"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('notifRemise', $serialize_permission)) {
|
||||
if (in_array('refusedRemise', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
@ -569,15 +521,13 @@
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td>-</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="deleteCommande1"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('deleteCommande1', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sécurité</td>
|
||||
@ -607,13 +557,6 @@
|
||||
echo "checked";
|
||||
}
|
||||
} ?>> </td>
|
||||
<td>-</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="notifSecurite"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('notifSecurite', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
@ -644,13 +587,6 @@
|
||||
echo "checked";
|
||||
}
|
||||
} ?>> </td>
|
||||
<td>-</td>
|
||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="notifAvance"
|
||||
<?php if ($serialize_permission) {
|
||||
if (in_array('notifAvance', $serialize_permission)) {
|
||||
echo "checked";
|
||||
}
|
||||
} ?>></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
@ -665,7 +601,6 @@
|
||||
} ?>></td>
|
||||
<td> - </td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Entreprise</td>
|
||||
@ -680,7 +615,6 @@
|
||||
<td> - </td>
|
||||
<td> - </td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Profile</td>
|
||||
@ -694,7 +628,6 @@
|
||||
} ?>></td>
|
||||
<td> - </td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
@ -709,7 +642,6 @@
|
||||
} ?>></td>
|
||||
<td> - </td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
@ -725,7 +657,6 @@
|
||||
<td> - </td>
|
||||
<td> - </td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -73,9 +73,8 @@
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Produit</th>
|
||||
<th>N° de série</th>
|
||||
<th>SKU</th>
|
||||
<th>Magasin</th>
|
||||
<th>Utilisateur</th>
|
||||
<th>Action</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
@ -239,14 +238,13 @@ $(document).ready(function() {
|
||||
"complete": function() { $("#loading").hide(); }
|
||||
},
|
||||
"columns": [
|
||||
{ "data": 0, "width": "13%" },
|
||||
{ "data": 1, "width": "15%" },
|
||||
{ "data": 0, "width": "15%" },
|
||||
{ "data": 1, "width": "20%" },
|
||||
{ "data": 2, "width": "10%" },
|
||||
{ "data": 3, "width": "12%" },
|
||||
{ "data": 4, "width": "10%" },
|
||||
{
|
||||
"data": 5,
|
||||
"width": "8%",
|
||||
"data": 4,
|
||||
"width": "10%",
|
||||
"render": function(data) {
|
||||
let badgeClass = "badge bg-gray";
|
||||
if (data === "CREATE") badgeClass = "badge bg-green";
|
||||
@ -256,7 +254,7 @@ $(document).ready(function() {
|
||||
return '<span class="'+badgeClass+'">'+data+'</span>';
|
||||
}
|
||||
},
|
||||
{ "data": 6, "width": "32%" }
|
||||
{ "data": 5, "width": "33%" }
|
||||
],
|
||||
"order": [[0, "desc"]],
|
||||
"pageLength": 25,
|
||||
|
||||
@ -52,6 +52,14 @@
|
||||
</div>
|
||||
<!-- /.box-header -->
|
||||
<form role="form" action="<?php base_url('orders/create') ?>" method="post" class="form-horizontal">
|
||||
<?php if (isset($validation) && $validation->getErrors()): ?>
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
<?= $validation->listErrors() ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
<div class="box-body">
|
||||
|
||||
|
||||
@ -100,31 +108,6 @@
|
||||
placeholder="Entrer ne CIN du client" autocomplete="off" required value="<?= old('customer_cin') ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="customer_type" class="col-sm-5 control-label" style="text-align:left;">Type de client <span class="text-danger">*</span></label>
|
||||
<div class="col-sm-7">
|
||||
<select class="form-control" id="customer_type" name="customer_type" required>
|
||||
<option value="">-- Sélectionner --</option>
|
||||
<option value="particulier" <?= old('customer_type') == 'particulier' ? 'selected' : '' ?>>Particulier</option>
|
||||
<option value="revendeur" <?= old('customer_type') == 'revendeur' ? 'selected' : '' ?>>Revendeur</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="source" class="col-sm-5 control-label" style="text-align:left;">Source <span class="text-danger">*</span></label>
|
||||
<div class="col-sm-7">
|
||||
<select class="form-control" id="source" name="source" required>
|
||||
<option value="">-- Sélectionner --</option>
|
||||
<option value="facebook_perso" <?= old('source') == 'facebook_perso' ? 'selected' : '' ?>>Facebook perso</option>
|
||||
<option value="page_motorbike" <?= old('source') == 'page_motorbike' ? 'selected' : '' ?>>Page motorbike</option>
|
||||
<option value="bouche_a_oreille" <?= old('source') == 'bouche_a_oreille' ? 'selected' : '' ?>>Bouche à oreille</option>
|
||||
<option value="commercial_interne" <?= old('source') == 'commercial_interne' ? 'selected' : '' ?>>Commercial interne</option>
|
||||
<option value="autre" <?= old('source') == 'autre' ? 'selected' : '' ?>>Autre</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@ -273,29 +256,6 @@
|
||||
'<i class="glyphicon glyphicon-tag"></i>' +
|
||||
'</button>';
|
||||
|
||||
// Gérer la visibilité du bouton "+" selon le type de client
|
||||
function toggleAddRowButton() {
|
||||
var customerType = $("#customer_type").val();
|
||||
var rowCount = $("#product_info_table tbody tr").length;
|
||||
|
||||
if (customerType === 'particulier' && rowCount >= 1) {
|
||||
$("#add_row").hide();
|
||||
} else {
|
||||
$("#add_row").show();
|
||||
}
|
||||
}
|
||||
|
||||
// Écouter le changement de type de client
|
||||
$("#customer_type").on('change', function () {
|
||||
var customerType = $(this).val();
|
||||
if (customerType === 'particulier') {
|
||||
// Supprimer toutes les lignes sauf la première
|
||||
$("#product_info_table tbody tr:gt(0)").remove();
|
||||
subAmount();
|
||||
}
|
||||
toggleAddRowButton();
|
||||
});
|
||||
|
||||
// Add new row in the table
|
||||
$("#add_row").unbind('click').bind('click', function () {
|
||||
var table = $("#product_info_table");
|
||||
@ -308,6 +268,7 @@
|
||||
dataType: 'json',
|
||||
success: function (response) {
|
||||
|
||||
// console.log(reponse.x);
|
||||
var html = '<tr id="row_' + row_id + '">' +
|
||||
'<td>' +
|
||||
'<select class="form-control select_group product" data-row-id="' + row_id + '" id="product_' + row_id + '" name="product[]" style="width:100%;" onchange="getProductData(' + row_id + ')">' +
|
||||
@ -335,9 +296,6 @@
|
||||
|
||||
$(".product").select2();
|
||||
|
||||
// Cacher le bouton "+" si particulier et déjà 2 lignes
|
||||
toggleAddRowButton();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@ -455,7 +413,6 @@
|
||||
function removeRow(tr_id) {
|
||||
$("#product_info_table tbody tr#row_" + tr_id).remove();
|
||||
subAmount();
|
||||
toggleAddRowButton();
|
||||
}
|
||||
function formatAllNumbers() {
|
||||
// Sélecteur pour tous les inputs que tu veux formater
|
||||
|
||||
@ -344,7 +344,7 @@
|
||||
|
||||
<?php
|
||||
$users = session()->get('user');
|
||||
if ($users && $users['group_name'] !== 'COMMERCIALE'):
|
||||
if ($users && $users['group_name'] === 'Caissière'):
|
||||
?>
|
||||
|
||||
<div class="form-group">
|
||||
@ -365,7 +365,7 @@
|
||||
<input type="hidden" name="vat_charge_rate" value="<?php echo $company_data['vat_charge_value'] ?>" autocomplete="off">
|
||||
|
||||
<a target="__blank" id="Imprimente" href="<?php echo base_url() . 'orders/printDiv/' . $order_data['order']['id'] ?>" class="btn btn-default">Imprimer</a>
|
||||
<button type="submit" class="btn btn-primary">Payer</button>
|
||||
<button type="submit" class="btn btn-primary">Enregistrer</button>
|
||||
<a href="<?php echo base_url('orders/') ?>" class="btn btn-warning">Retour</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
<h3 class="box-title">Mise à jours Moto</h3>
|
||||
</div>
|
||||
|
||||
<form role="form" action="<?php echo base_url('products/update/' . $product_data['id']); ?>" method="post" enctype="multipart/form-data">
|
||||
<form role="form" action="<?php base_url('users/update') ?>" method="post" enctype="multipart/form-data">
|
||||
<div class="box-body">
|
||||
<!-- Image actuelle -->
|
||||
<div class="form-group">
|
||||
@ -111,7 +111,7 @@
|
||||
<!-- Date d'arrivage -->
|
||||
<div class="form-group">
|
||||
<label for="datea">Date d'arrivage</label>
|
||||
<input type="date" class="form-control" id="datea" name="datea" autocomplete="off" value="<?php echo !empty($product_data['date_arivage']) ? date('Y-m-d', strtotime($product_data['date_arivage'])) : ''; ?>" />
|
||||
<input type="date" class="form-control" id="datea" name="datea" autocomplete="off" value="<?php echo $product_data['date_arivage']; ?>" />
|
||||
</div>
|
||||
|
||||
<!-- Puissance -->
|
||||
@ -143,23 +143,19 @@
|
||||
<label for="categorie">Catégories</label>
|
||||
<?php
|
||||
$rawCats = $product_data['categorie_id'] ?? null;
|
||||
$catIds = [];
|
||||
if (is_array($rawCats)) {
|
||||
$catIds = array_map('intval', $rawCats);
|
||||
} elseif (is_string($rawCats)) {
|
||||
$decoded = json_decode($rawCats, true);
|
||||
if (is_array($decoded)) {
|
||||
$catIds = array_map('intval', $decoded);
|
||||
} else {
|
||||
$catIds = array_filter(array_map('intval', explode(',', $rawCats)), fn($id) => $id > 0);
|
||||
}
|
||||
} elseif (is_int($rawCats) || ctype_digit((string)$rawCats)) {
|
||||
$catIds = [(int) $rawCats];
|
||||
} else {
|
||||
$catIds = [];
|
||||
}
|
||||
?>
|
||||
<select class="form-control select_group" id="categorie" name="categorie[]" multiple="multiple">
|
||||
<?php foreach ($categorie as $k => $v): ?>
|
||||
<option value="<?= $v['id']; ?>" <?= in_array((int)$v['id'], $catIds) ? 'selected="selected"' : '' ?>><?= esc($v['name']); ?></option>
|
||||
<option value="<?= $v['id']; ?>" <?= in_array($v['id'], $catIds, true) ? 'selected="selected"' : '' ?>><?= esc($v['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@ -155,7 +155,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Image</th>
|
||||
<th>N° SERIE </th>
|
||||
<th>UGS</th>
|
||||
<th>Nom de produit</th>
|
||||
<th>Prix</th>
|
||||
<th>Magasin</th>
|
||||
@ -340,12 +340,7 @@
|
||||
'columnDefs': [{
|
||||
targets: 3,
|
||||
className: 'text-right'
|
||||
}],
|
||||
'createdRow': function(row, data, dataIndex) {
|
||||
if (data[5] && data[5].indexOf('En attente de livraison') !== -1) {
|
||||
$(row).css({'background-color': '#fff3cd', 'opacity': '0.85'});
|
||||
}
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
// CORRECTION: Utilisation de la délégation d'événements pour les boutons
|
||||
|
||||
@ -67,9 +67,7 @@
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<?php if (in_array('updateRecouvrement', $user_permission) || in_array('deleteRecouvrement', $user_permission)): ?>
|
||||
<td></td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -277,7 +275,7 @@
|
||||
// Initialisation du DataTable
|
||||
manageTable = $('#manageTable').DataTable({
|
||||
'ajax': '<?= base_url('recouvrement/fetchRecouvrementData') ?>',
|
||||
'order': [[2, 'desc']],
|
||||
'order': [],
|
||||
'columnDefs': [{
|
||||
targets: 1,
|
||||
className: 'text-right rowmontant'
|
||||
@ -308,30 +306,12 @@
|
||||
})
|
||||
|
||||
// ====== CRÉATION DE RECOUVREMENT ======
|
||||
$("#create_form").unbind('submit').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
$("#create_form").unbind('submit').on('submit', function() {
|
||||
var form = $(this);
|
||||
var submitBtn = form.find('button[type="submit"]');
|
||||
|
||||
// Supprimer les messages d'erreur
|
||||
$(".text-danger").remove();
|
||||
|
||||
// Pop-up de confirmation
|
||||
Swal.fire({
|
||||
title: 'Confirmer la création',
|
||||
text: 'Voulez-vous vraiment enregistrer ce recouvrement ?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: 'Oui, enregistrer',
|
||||
cancelButtonText: 'Annuler'
|
||||
}).then((result) => {
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
// Désactiver le bouton pour éviter les doublons
|
||||
submitBtn.prop('disabled', true).text('Enregistrement...');
|
||||
|
||||
$.ajax({
|
||||
url: form.attr('action'),
|
||||
type: form.attr('method'),
|
||||
@ -394,15 +374,9 @@ $("#create_form").unbind('submit').on('submit', function(e) {
|
||||
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' +
|
||||
'<strong>Erreur!</strong> Une erreur est survenue lors de la création.' +
|
||||
'</div>');
|
||||
},
|
||||
complete: function() {
|
||||
// Réactiver le bouton
|
||||
submitBtn.prop('disabled', false).text('Enregistrer');
|
||||
}
|
||||
});
|
||||
|
||||
}); // fin Swal.then
|
||||
|
||||
return false;
|
||||
});
|
||||
// ====== SUPPRESSION DE RECOUVREMENT ======
|
||||
|
||||
@ -13,9 +13,8 @@
|
||||
<section class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-xs-12">
|
||||
<form action="<?php echo base_url('reports/'); ?>" method="POST">
|
||||
<div class="row" style="margin-bottom: 15px;">
|
||||
<div class="col-md-2">
|
||||
<form class="form-inline" action="<?php echo base_url('reports/'); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label for="select_year">Année</label>
|
||||
<select class="form-control" name="select_year" id="select_year">
|
||||
<?php foreach ($report_years as $value): ?>
|
||||
@ -25,47 +24,8 @@
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label for="start_date">Date début</label>
|
||||
<input type="date" class="form-control" name="start_date" id="start_date" value="<?= $selected_start_date ?? '' ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label for="end_date">Date fin</label>
|
||||
<input type="date" class="form-control" name="end_date" id="end_date" value="<?= $selected_end_date ?? '' ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label for="store_id">Point de vente</label>
|
||||
<select class="form-control" name="store_id" id="store_id">
|
||||
<option value="">TOUS</option>
|
||||
<?php foreach ($stores as $store): ?>
|
||||
<option value="<?= $store['id'] ?>" <?= (isset($selected_store_id) && $selected_store_id == $store['id']) ? 'selected' : '' ?>>
|
||||
<?= $store['name'] ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label for="user_id">Utilisateur</label>
|
||||
<select class="form-control" name="user_id" id="user_id">
|
||||
<option value="">TOUS</option>
|
||||
<?php foreach ($users_list as $u): ?>
|
||||
<option value="<?= $u['id'] ?>" <?= (isset($selected_user_id) && $selected_user_id == $u['id']) ? 'selected' : '' ?>>
|
||||
<?= $u['firstname'] . ' ' . $u['lastname'] ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2" style="padding-top: 25px;">
|
||||
<button type="submit" class="btn btn-primary"><i class="fa fa-filter"></i> Filtrer</button>
|
||||
<a href="<?= base_url('reports/') ?>" class="btn btn-default" title="Réinitialiser"><i class="fa fa-refresh"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-bottom: 10px;">
|
||||
<div class="col-md-12">
|
||||
<a href="<?= base_url('reports/detail/stock') ?>" class="btn btn-sm btn-success">Details Stock</a>
|
||||
<a href="<?= base_url('reports/detail/performance') ?>" class="btn btn-sm btn-primary">Performances</a>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Envoyer</button>
|
||||
<a href="detail/stock" class="btn btn-sm btn-success">Détails</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
@ -73,28 +73,27 @@
|
||||
<label for="endDate" class="form-label">Date de fin</label>
|
||||
<input type="date" id="endDate" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="col-md-3">
|
||||
<label for="pvente" class="form-label">Points de ventes</label>
|
||||
<select id="pvente" class="form-control">
|
||||
<select name="" id="pvente" class="form-control">
|
||||
<option value="TOUS">TOUS</option>
|
||||
<?php foreach ($stores as $value): ?>
|
||||
<option value="<?= $value['name']; ?>"><?= $value['name']; ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php
|
||||
foreach ($stores as $value) {
|
||||
?>
|
||||
<option value="<?= $value['name']; ?>"><?= $value['name']; ?>
|
||||
</option>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label for="commercialFilter" class="form-label">Commercial</label>
|
||||
<select id="commercialFilter" class="form-control">
|
||||
<option value="TOUS">TOUS</option>
|
||||
<?php foreach ($commerciaux as $com): ?>
|
||||
<option value="<?= $com['id']; ?>"><?= $com['firstname'] . ' ' . $com['lastname']; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex align-items-end">
|
||||
<div class="col-md-3 d-flex align-items-end">
|
||||
<br>
|
||||
<button id="filteredB1" class="btn btn-primary w-100">Filtrer</button>
|
||||
<button id="ExportBTN1" class="btn btn-success w-100">Exporter</button>
|
||||
<button id="filteredB1" class="btn btn-primary w-100">Filtrer
|
||||
🔍</button>
|
||||
<button id="ExportBTN1" class="btn btn-success w-100">Exporter
|
||||
📤</button>
|
||||
</div>
|
||||
</div>
|
||||
<table id="commperformance" class="table table-hover table-striped">
|
||||
@ -103,7 +102,7 @@
|
||||
<th>Nom et prénom</th>
|
||||
<th>Email</th>
|
||||
<th>Motos vendue</th>
|
||||
<th>Date de vente</th>
|
||||
<th>Date de vente</th><!-- return 2025-04-18 -->
|
||||
<th>Prix d'achat</th>
|
||||
<th>Prix de vente</th>
|
||||
<th>Point de ventes</th>
|
||||
@ -113,9 +112,9 @@
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th colspan="5" style="text-align:right">Total:</th>
|
||||
<th></th> <!-- total Prix de vente -->
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th> <!-- total Bénéfices -->
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
@ -136,48 +135,48 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3 align-items-center mb-4" style="margin: 5px 0 5px 5px;">
|
||||
<div class="col-md-2">
|
||||
<div class="col-md-3">
|
||||
<label for="startDate2" class="form-label">Date de début</label>
|
||||
<input type="date" id="startDate2" class="form-control">
|
||||
<input type="date" id="startDate" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="col-md-3">
|
||||
<label for="endDate2" class="form-label">Date de fin</label>
|
||||
<input type="date" id="endDate2" class="form-control">
|
||||
<input type="date" id="endDate" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label for="pvente2" class="form-label">Points de ventes</label>
|
||||
<select id="pvente2" class="form-control">
|
||||
<div class="col-md-3">
|
||||
<label for="pvente" class="form-label">Points de ventes</label>
|
||||
<select name="" id="pvente2" class="form-control">
|
||||
<option value="TOUS">TOUS</option>
|
||||
<?php foreach ($stores as $value): ?>
|
||||
<option value="<?= $value['name']; ?>"><?= $value['name']; ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php
|
||||
foreach ($stores as $value) {
|
||||
?>
|
||||
<option value="<?= $value['name']; ?>"><?= $value['name']; ?>
|
||||
</option>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label for="mecanicienFilter" class="form-label">Mécanicien</label>
|
||||
<select id="mecanicienFilter" class="form-control">
|
||||
<option value="TOUS">TOUS</option>
|
||||
<?php foreach ($mecaniciens as $mec): ?>
|
||||
<option value="<?= $mec['id']; ?>"><?= $mec['firstname'] . ' ' . $mec['lastname']; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex align-items-end">
|
||||
<div class="col-md-3 d-flex align-items-end">
|
||||
<br>
|
||||
<button id="filteredB2" class="btn btn-primary w-100">Filtrer</button>
|
||||
<button id="ExportBTN2" class="btn btn-success w-100">Exporter</button>
|
||||
<button id="filteredB2" class="btn btn-primary w-100">Filtrer
|
||||
🔍</button>
|
||||
<button id="ExportBTN2" class="btn btn-success w-100">Exporter
|
||||
📤</button>
|
||||
</div>
|
||||
</div>
|
||||
<table id="mecperformance" class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Mécanicien</th>
|
||||
<th>Image</th>
|
||||
<th>Moto réparée</th>
|
||||
<th>N° Série</th>
|
||||
<th>Point de vente</th>
|
||||
<th>Date début</th>
|
||||
<th>Date fin</th>
|
||||
<th>Nom et prénom</th>
|
||||
<th>Email</th>
|
||||
<th>Motos vendue</th>
|
||||
<th>Date de vente</th><!-- return 2025-04-18 -->
|
||||
<th>Prix d'achat</th>
|
||||
<th>Prix de vente</th>
|
||||
<th>Point de ventes</th>
|
||||
<th>Bénefices</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
@ -201,10 +200,8 @@
|
||||
|
||||
// Initialize the datatable
|
||||
|
||||
var baseUrl = '<?= base_url() ?>';
|
||||
|
||||
manageTable = $('#commperformance').DataTable({
|
||||
'ajax': baseUrl + 'reports/detail/fetchPerformances',
|
||||
'ajax': 'fetchPerformances',
|
||||
'order': [],
|
||||
'pageLength': 5,
|
||||
'lengthMenu': [
|
||||
@ -244,44 +241,49 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Filtre commercial - côté serveur
|
||||
$('#filteredB1').on('click', function () {
|
||||
var startDate = $('#startDate').val();
|
||||
var endDate = $('#endDate').val();
|
||||
var pvente = $('#pvente').val();
|
||||
var commercial = $('#commercialFilter').val();
|
||||
const startDate = $('#startDate').val();
|
||||
const endDate = $('#endDate').val();
|
||||
const pvente = $('#pvente').val();
|
||||
|
||||
var url = baseUrl + 'reports/detail/fetchPerformances?startDate=' + startDate + '&endDate=' + endDate + '&pvente=' + pvente + '&commercial=' + commercial;
|
||||
manageTable.ajax.url(url).load();
|
||||
// Get all original data (you may need to fetch from server or already loaded)
|
||||
manageTable.ajax.url('fetchPerformances').load(function () {
|
||||
const filteredData = [];
|
||||
|
||||
manageTable.rows().every(function () {
|
||||
const data = this.data();
|
||||
const saleDate = data[3].split(' ')[0]; // extract YYYY-MM-DD from date
|
||||
const store = data[6];
|
||||
|
||||
// Filter logic
|
||||
const dateMatch = (!startDate && !endDate) ||
|
||||
(startDate && endDate && saleDate >= startDate && saleDate <= endDate) ||
|
||||
(startDate && !endDate && saleDate >= startDate) ||
|
||||
(!startDate && endDate && saleDate <= endDate);
|
||||
|
||||
const storeMatch = (pvente === 'TOUS' || pvente === store);
|
||||
|
||||
if (dateMatch && storeMatch) {
|
||||
filteredData.push(data);
|
||||
}
|
||||
});
|
||||
|
||||
// DataTable mécanicien
|
||||
var mecTable = $('#mecperformance').DataTable({
|
||||
'ajax': baseUrl + 'mecanicien/fetchMecanicienPerformances',
|
||||
'order': [],
|
||||
'pageLength': 10
|
||||
// Clear and reload table with filtered data
|
||||
manageTable.clear().rows.add(filteredData).draw();
|
||||
});
|
||||
|
||||
// Filtre mécanicien - côté serveur
|
||||
$('#filteredB2').on('click', function () {
|
||||
var startDate = $('#startDate2').val();
|
||||
var endDate = $('#endDate2').val();
|
||||
var mecanic = $('#mecanicienFilter').val();
|
||||
|
||||
var url = baseUrl + 'mecanicien/fetchMecanicienPerformances?startDate=' + startDate + '&endDate=' + endDate + '&mecanic_id=' + (mecanic === 'TOUS' ? '' : mecanic);
|
||||
mecTable.ajax.url(url).load();
|
||||
});
|
||||
});
|
||||
|
||||
// Export commercial
|
||||
document.getElementById('ExportBTN1').addEventListener('click', function () {
|
||||
var wb = XLSX.utils.table_to_book(document.getElementById('commperformance'), { sheet: "Commercial" });
|
||||
// Select your table
|
||||
var table = document.getElementById('commperformance');
|
||||
|
||||
// Convert it to a workbook
|
||||
var wb = XLSX.utils.table_to_book(table, {
|
||||
sheet: "Feuille1"
|
||||
});
|
||||
|
||||
// Export it
|
||||
XLSX.writeFile(wb, 'export-commercial-performance.xlsx');
|
||||
});
|
||||
|
||||
// Export mécanicien
|
||||
document.getElementById('ExportBTN2').addEventListener('click', function () {
|
||||
var wb = XLSX.utils.table_to_book(document.getElementById('mecperformance'), { sheet: "Mecanicien" });
|
||||
XLSX.writeFile(wb, 'export-mecanicien-performance.xlsx');
|
||||
});
|
||||
</script>
|
||||
@ -57,17 +57,9 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- Filter Bar -->
|
||||
<div class="row g-3 align-items-center mb-3" style="margin: 5px 0;">
|
||||
<div class="col-md-2">
|
||||
<label for="startDateStock" class="form-label fw-bold">Date de début</label>
|
||||
<input type="date" id="startDateStock" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label for="endDateStock" class="form-label fw-bold">Date de fin</label>
|
||||
<input type="date" id="endDateStock" class="form-control">
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-3">
|
||||
<label for="storeFilter" class="form-label fw-bold">Points de ventes</label>
|
||||
<label for="storeFilter" class="form-label fw-bold">🏪 Points de ventes</label>
|
||||
<select id="storeFilter" class="form-control">
|
||||
<option value="TOUS">TOUS</option>
|
||||
<?php foreach ($stores as $value) { ?>
|
||||
@ -75,9 +67,9 @@
|
||||
<?php } ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex align-items-end">
|
||||
<div class="col-md-3 d-flex align-items-end">
|
||||
<br>
|
||||
<button id="filterBtn" class="btn btn-primary w-100">Filtrer</button>
|
||||
<button id="filterBtn" class="btn btn-primary w-100">🔍 Filtrer</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -136,27 +128,20 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3 align-items-center mb-4" style="margin: 5px 0 5px 5px;">
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
<label for="startDate" class="form-label">Date de début</label>
|
||||
<input type="date" id="startDate" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
<label for="endDate" class="form-label">Date de fin</label>
|
||||
<input type="date" id="endDate" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="exportStoreFilter" class="form-label">Point de vente</label>
|
||||
<select id="exportStoreFilter" class="form-control">
|
||||
<option value="TOUS">TOUS</option>
|
||||
<?php foreach ($stores as $value) { ?>
|
||||
<option value="<?= $value['id'] ?>"><?= $value['name'] ?></option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 d-flex align-items-end">
|
||||
<div class="col-md-4 d-flex align-items-end">
|
||||
<br>
|
||||
<button id="filteredB1" class="btn btn-primary w-100">Filtrer</button>
|
||||
<button id="ExportBTN1" class="btn btn-success w-100">Exporter</button>
|
||||
<button id="filteredB1" class="btn btn-primary w-100">Filtrer
|
||||
🔍</button>
|
||||
<button id="ExportBTN1" class="btn btn-success w-100">Exporter
|
||||
📤</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -203,7 +188,7 @@
|
||||
|
||||
|
||||
manageTable = $('#venteTable').DataTable({
|
||||
'ajax': 'fetchData/' + 0,
|
||||
'ajax': 'fetctData/' + 0,
|
||||
'order': [],
|
||||
'pageLength': 5, // Set default rows per page
|
||||
'lengthMenu': [
|
||||
@ -213,7 +198,7 @@
|
||||
});
|
||||
|
||||
manageTable2 = $('#stockTable').DataTable({
|
||||
'ajax': 'fetchDataStock/' + 0,
|
||||
'ajax': 'fetctDataStock/' + 0,
|
||||
'order': [],
|
||||
'pageLength': 5, // Set default rows per page
|
||||
'lengthMenu': [
|
||||
@ -224,7 +209,7 @@
|
||||
|
||||
manageTable3 = $('#export1').DataTable({
|
||||
ajax: {
|
||||
url: 'fetchDataStock2/' + 0,
|
||||
url: 'fetctDataStock2/' + 0,
|
||||
dataSrc: 'data'
|
||||
},
|
||||
order: [],
|
||||
@ -235,16 +220,14 @@
|
||||
]
|
||||
});
|
||||
|
||||
const storeSelect = document.getElementById('storeFilter');
|
||||
const filterBtn = document.getElementById('storeFilter');
|
||||
|
||||
storeSelect.addEventListener('change', function () {
|
||||
let filterValue = storeSelect.value === "TOUS" ? "0" : storeSelect.value;
|
||||
let startDate = $('#startDateStock').val();
|
||||
let endDate = $('#endDateStock').val();
|
||||
let params = '?startDate=' + startDate + '&endDate=' + endDate;
|
||||
filterBtn.addEventListener('change', function () {
|
||||
let filterValue = filterBtn.value === "TOUS" ? "0" : filterBtn.value;
|
||||
|
||||
manageTable.ajax.url('fetchData/' + filterValue + params).load();
|
||||
manageTable2.ajax.url('fetchDataStock/' + filterValue + params).load();
|
||||
// Update the DataTable dynamically without reinitialization
|
||||
manageTable.ajax.url('fetctData/' + filterValue).load();
|
||||
manageTable2.ajax.url('fetctDataStock/' + filterValue).load();
|
||||
});
|
||||
|
||||
let productsSold = <?= $ventes ?>;
|
||||
@ -266,14 +249,6 @@
|
||||
// Trigger the filter on button click
|
||||
$('#filterBtn').click(function () {
|
||||
let storeId = $('#storeFilter').val();
|
||||
let filterValue = storeId === "TOUS" ? "0" : storeId;
|
||||
let startDate = $('#startDateStock').val();
|
||||
let endDate = $('#endDateStock').val();
|
||||
let params = '?startDate=' + startDate + '&endDate=' + endDate;
|
||||
|
||||
manageTable.ajax.url('fetchData/' + filterValue + params).load();
|
||||
manageTable2.ajax.url('fetchDataStock/' + filterValue + params).load();
|
||||
manageTable3.ajax.url('fetchDataStock2/' + filterValue + params).load();
|
||||
applyFilter(storeId);
|
||||
});
|
||||
|
||||
@ -281,14 +256,32 @@
|
||||
applyFilter("TOUS");
|
||||
});
|
||||
|
||||
$('#filteredB1').on('click', function () {
|
||||
let storeId = $('#exportStoreFilter').val();
|
||||
let filterValue = storeId === "TOUS" ? "0" : storeId;
|
||||
let startDate = $('#startDate').val();
|
||||
let endDate = $('#endDate').val();
|
||||
let params = '?startDate=' + startDate + '&endDate=' + endDate;
|
||||
$.fn.dataTable.ext.search.push(function (settings, data, dataIndex) {
|
||||
if (settings.nTable.id !== 'export1') return true; // Apply only to your table
|
||||
|
||||
manageTable3.ajax.url('fetchDataStock2/' + filterValue + params).load();
|
||||
const startDate = $('#startDate').val();
|
||||
const endDate = $('#endDate').val();
|
||||
const saleDate = data[3]; // assuming column 4 is "Date de vente"
|
||||
|
||||
// If no start date, show everything (default)
|
||||
if (!startDate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const sale = new Date(saleDate);
|
||||
const start = new Date(startDate);
|
||||
const end = endDate ? new Date(endDate) : null;
|
||||
|
||||
if (end) {
|
||||
return sale >= start && sale <= end;
|
||||
} else {
|
||||
return sale >= start;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('#filteredB1').on('click', function () {
|
||||
manageTable3.draw(); // re-filter table
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -186,33 +186,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ✅ COMMANDES EN ATTENTE DE VALIDATION -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<i class="fa fa-clock-o"></i> Commandes en attente de livraison
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<table id="pendingTable" class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Image</th>
|
||||
<th>N° SERIE </th>
|
||||
<th>Désignation</th>
|
||||
<th>Statut</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filtres -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
@ -272,7 +245,7 @@
|
||||
<th>Image</th>
|
||||
<th>N° Facture</th>
|
||||
<th>Désignation</th>
|
||||
<th>N° SERIE </th>
|
||||
<th>UGS</th>
|
||||
<th>Marque</th>
|
||||
<th>Client</th>
|
||||
<th>Magasin</th>
|
||||
@ -293,38 +266,6 @@
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Modal de validation livraison -->
|
||||
<div class="modal fade" id="editModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" style="background: linear-gradient(135deg, #28a745 0%, #20c997 100%); color: white;">
|
||||
<button type="button" class="close" data-dismiss="modal" style="color: white;">×</button>
|
||||
<h4 class="modal-title"><i class="fa fa-check-circle"></i> Valider la livraison</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4 text-center">
|
||||
<img id="editImage" class="img-responsive img-thumbnail" src="" alt="Produit" style="max-height: 200px;">
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<p><strong>Produit :</strong> <span id="editNom"></span></p>
|
||||
<p><strong>N° SERIE :</strong> <span id="editNumSerie"></span></p>
|
||||
<p><strong>N° Facture :</strong> <span id="editBillNo"></span></p>
|
||||
<p><strong>Client :</strong> <span id="editClient"></span></p>
|
||||
<p><strong>Adresse :</strong> <span id="editAddress"></span></p>
|
||||
<p><strong>Téléphone :</strong> <span id="editPhone"></span></p>
|
||||
<p><strong>CIN :</strong> <span id="editCin"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Annuler</button>
|
||||
<button type="button" class="btn btn-success" id="btnValidate"><i class="fa fa-check"></i> Confirmer la livraison</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Détails -->
|
||||
<div class="modal fade" id="detailsModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
@ -353,8 +294,8 @@
|
||||
<div class="col-xs-6"><span id="detailDesignation"></span></div>
|
||||
</div>
|
||||
<div class="row" style="margin-bottom: 15px;">
|
||||
<div class="col-xs-6"><strong>N° SERIE:</strong></div>
|
||||
<div class="col-xs-6"><span id="detailNumSerie"></span></div>
|
||||
<div class="col-xs-6"><strong>UGS:</strong></div>
|
||||
<div class="col-xs-6"><span id="detailUGS"></span></div>
|
||||
</div>
|
||||
<div class="row" style="margin-bottom: 15px;">
|
||||
<div class="col-xs-6"><strong>Marque:</strong></div>
|
||||
@ -421,94 +362,6 @@
|
||||
$(function() {
|
||||
$("#securiteNav").addClass('active');
|
||||
|
||||
// ✅ TABLEAU DES COMMANDES EN ATTENTE
|
||||
var pendingTable = $('#pendingTable').DataTable({
|
||||
ajax: {
|
||||
url: '<?= base_url('validateSecurite/fetchSecuriteData') ?>',
|
||||
type: 'GET',
|
||||
dataSrc: 'data'
|
||||
},
|
||||
columns: [
|
||||
{ data: 'image', orderable: false },
|
||||
{ data: 'num_serie' },
|
||||
{ data: 'designation' },
|
||||
{ data: 'statut' },
|
||||
{ data: 'action', orderable: false }
|
||||
],
|
||||
order: [],
|
||||
language: {
|
||||
sProcessing: "Traitement en cours...",
|
||||
sSearch: "Rechercher :",
|
||||
sZeroRecords: "Aucune commande en attente",
|
||||
sEmptyTable: "Aucune commande en attente de livraison",
|
||||
sInfo: "Affichage de _START_ à _END_ sur _TOTAL_ éléments",
|
||||
sInfoEmpty: "Aucun élément",
|
||||
oPaginate: { sPrevious: "Précédent", sNext: "Suivant" }
|
||||
}
|
||||
});
|
||||
|
||||
// Rafraîchir les commandes en attente toutes les 10 secondes
|
||||
setInterval(function() { pendingTable.ajax.reload(null, false); }, 10000);
|
||||
|
||||
// ✅ GESTION DE LA VALIDATION
|
||||
var currentSecuriteId = null;
|
||||
|
||||
window.editFunc = function(id) {
|
||||
currentSecuriteId = id;
|
||||
$.ajax({
|
||||
url: '<?= base_url('validateSecurite/fetchSecuriteDataById') ?>/' + id,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
$('#editImage').attr('src', response.image);
|
||||
$('#editNom').text(response.nom);
|
||||
$('#editNumSerie').text(response.num_serie);
|
||||
$('#editBillNo').text(response.bill_no);
|
||||
$('#editClient').text(response.customer_name);
|
||||
$('#editAddress').text(response.customer_address);
|
||||
$('#editPhone').text(response.customer_phone);
|
||||
$('#editCin').text(response.customer_cin);
|
||||
$('#editModal').modal('show');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('#btnValidate').on('click', function() {
|
||||
if (!currentSecuriteId) return;
|
||||
var btn = $(this);
|
||||
btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Validation...');
|
||||
|
||||
$.ajax({
|
||||
url: '<?= base_url('validateSecurite/update') ?>/' + currentSecuriteId,
|
||||
type: 'POST',
|
||||
data: { status: 'Validé' },
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
$('#editModal').modal('hide');
|
||||
btn.prop('disabled', false).html('<i class="fa fa-check"></i> Confirmer la livraison');
|
||||
|
||||
if (response.success) {
|
||||
// Aussi marquer comme livré côté commande
|
||||
pendingTable.ajax.reload(null, false);
|
||||
if (typeof historyTable !== 'undefined') historyTable.ajax.reload(null, false);
|
||||
|
||||
$('#messages').html('<div class="alert alert-success alert-dismissible">' +
|
||||
'<button type="button" class="close" data-dismiss="alert">×</button>' +
|
||||
'<i class="fa fa-check"></i> ' + response.messages + '</div>');
|
||||
setTimeout(function() { $('#messages').fadeOut('slow', function() { $(this).html('').show(); }); }, 3000);
|
||||
} else {
|
||||
$('#messages').html('<div class="alert alert-danger alert-dismissible">' +
|
||||
'<button type="button" class="close" data-dismiss="alert">×</button>' +
|
||||
response.messages + '</div>');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
btn.prop('disabled', false).html('<i class="fa fa-check"></i> Confirmer la livraison');
|
||||
$('#editModal').modal('hide');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Configuration DataTable en français
|
||||
$.extend(true, $.fn.dataTable.defaults, {
|
||||
language: {
|
||||
@ -767,7 +620,7 @@ $(function() {
|
||||
data.push([
|
||||
'N° Facture',
|
||||
'Désignation',
|
||||
'N° SERIE',
|
||||
'UGS',
|
||||
'Marque',
|
||||
'Client',
|
||||
'Magasin',
|
||||
@ -818,7 +671,7 @@ function viewDetails(id) {
|
||||
$('#detailImage').attr('src', data[0]);
|
||||
$('#detailBillNo').text(data[1]);
|
||||
$('#detailDesignation').text(data[2]);
|
||||
$('#detailNumSerie').text(data[3]);
|
||||
$('#detailUGS').text(data[3]);
|
||||
$('#detailMarque').text(data[4]);
|
||||
$('#detailSerie').text(data[3]);
|
||||
$('#detailStore').text(data[7]);
|
||||
|
||||
@ -17,87 +17,26 @@ function toggleSidebar() {
|
||||
document.body.classList.toggle('sidebar-collapsed');
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
// Supprimer TOUS les handlers AdminLTE sur le menu
|
||||
$('.sidebar-menu').off();
|
||||
$(document).off('click', '.sidebar-menu li a');
|
||||
$(document).off('click', '.treeview > a');
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const treeviews = document.querySelectorAll('.sidebar-menu .treeview');
|
||||
|
||||
// Aussi tenter de détruire le widget tree AdminLTE
|
||||
try { $('.sidebar-menu').tree('destroy'); } catch(e) {}
|
||||
|
||||
// Re-supprimer après un court délai (AdminLTE peut rebind)
|
||||
setTimeout(function() {
|
||||
$('.sidebar-menu').off();
|
||||
bindSidebarMenu();
|
||||
}, 100);
|
||||
|
||||
function bindSidebarMenu() {
|
||||
// Clic sur un treeview
|
||||
$('.sidebar-menu .treeview > a').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
var $li = $(this).parent();
|
||||
var menuId = $li.attr('id') || $('.sidebar-menu .treeview').index($li);
|
||||
|
||||
// Fermer les autres
|
||||
$('.sidebar-menu .treeview').not($li).removeClass('menu-open')
|
||||
.children('.treeview-menu').slideUp(200);
|
||||
|
||||
// Toggle
|
||||
if ($li.hasClass('menu-open')) {
|
||||
$li.removeClass('menu-open');
|
||||
$li.children('.treeview-menu').slideUp(200);
|
||||
localStorage.removeItem('openMenu');
|
||||
} else {
|
||||
$li.addClass('menu-open');
|
||||
$li.children('.treeview-menu').slideDown(200);
|
||||
localStorage.setItem('openMenu', String(menuId));
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Restaurer le menu ouvert au survol de la sidebar
|
||||
var restored = false;
|
||||
$('.main-sidebar').on('mouseenter', function() {
|
||||
if (!restored && $('body').hasClass('sidebar-collapsed')) {
|
||||
var openMenu = localStorage.getItem('openMenu');
|
||||
if (openMenu !== null) {
|
||||
var $target = $('#' + openMenu);
|
||||
if (!$target.length) {
|
||||
$target = $('.sidebar-menu .treeview').eq(parseInt(openMenu));
|
||||
}
|
||||
if ($target.length) {
|
||||
$target.addClass('menu-open');
|
||||
$target.children('.treeview-menu').slideDown(200);
|
||||
}
|
||||
}
|
||||
restored = true;
|
||||
treeviews.forEach(item => {
|
||||
// Quand la souris entre dans un menu
|
||||
item.addEventListener('mouseenter', function () {
|
||||
if (document.body.classList.contains('sidebar-collapsed')) {
|
||||
this.classList.add('menu-open');
|
||||
}
|
||||
});
|
||||
|
||||
// Quand la souris quitte : fermer visuellement mais garder en mémoire
|
||||
var closeTimer = null;
|
||||
$('.main-sidebar').on('mouseleave', function() {
|
||||
if ($('body').hasClass('sidebar-collapsed')) {
|
||||
closeTimer = setTimeout(function() {
|
||||
$('.sidebar-menu .treeview').removeClass('menu-open');
|
||||
$('.sidebar-menu .treeview-menu').slideUp(200);
|
||||
restored = false;
|
||||
}, 400);
|
||||
// Quand la souris sort du menu
|
||||
item.addEventListener('mouseleave', function () {
|
||||
if (document.body.classList.contains('sidebar-collapsed')) {
|
||||
this.classList.remove('menu-open');
|
||||
}
|
||||
});
|
||||
$('.main-sidebar').on('mouseenter', function() {
|
||||
if (closeTimer) {
|
||||
clearTimeout(closeTimer);
|
||||
closeTimer = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
@ -5,13 +5,6 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title><?php echo $page_title; ?></title>
|
||||
<?php if (!empty($company_logo)): ?>
|
||||
<link rel="icon" type="image/x-icon" href="<?= base_url($company_logo) ?>?v=<?= time() ?>">
|
||||
<link rel="shortcut icon" href="<?= base_url($company_logo) ?>?v=<?= time() ?>">
|
||||
<?php else: ?>
|
||||
<link rel="icon" type="image/x-icon" href="<?= base_url('assets/images/company_logo.jpg') ?>?v=<?= time() ?>">
|
||||
<link rel="shortcut icon" href="<?= base_url('assets/images/company_logo.jpg') ?>?v=<?= time() ?>">
|
||||
<?php endif; ?>
|
||||
<!-- Tell the browser to be responsive to screen width -->
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<!-- Bootstrap 3.3.7 -->
|
||||
@ -125,7 +118,7 @@
|
||||
|
||||
</head>
|
||||
|
||||
<body class="hold-transition skin-blue sidebar-mini sidebar-collapsed">
|
||||
<body class="hold-transition skin-blue sidebar-mini">
|
||||
<div class="wrapper">
|
||||
<style>
|
||||
/* ============================================
|
||||
@ -134,26 +127,6 @@
|
||||
/* ============================================
|
||||
VARIABLES CSS - Design System Couleurs Unies
|
||||
============================================ */
|
||||
/* Fix select dropdowns */
|
||||
select.form-control {
|
||||
width: 100% !important;
|
||||
min-width: 0;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-appearance: menulist;
|
||||
-moz-appearance: menulist;
|
||||
appearance: menulist;
|
||||
padding-right: 30px !important;
|
||||
color: #333 !important;
|
||||
background-color: #fff !important;
|
||||
height: auto !important;
|
||||
min-height: 40px;
|
||||
}
|
||||
select.form-control option {
|
||||
color: #333;
|
||||
background: #fff;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
:root {
|
||||
--primary-color: #3498db;
|
||||
--success-color: #2ecc71;
|
||||
@ -173,12 +146,13 @@ body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Inter', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Source Sans Pro', sans-serif !important;
|
||||
overflow-x: hidden;
|
||||
min-height: 100vh;
|
||||
background: #3498db !important;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
margin-top:50px;
|
||||
margin-top:30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
@ -191,14 +165,14 @@ body {
|
||||
.content-wrapper {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 60px;
|
||||
margin-left: 230px;
|
||||
width: calc(100% - 230px);
|
||||
transition: margin-left 0.3s ease, width 0.3s ease;
|
||||
padding-top: 50px;
|
||||
transition: margin-left 0.3s ease;
|
||||
background: #ecf0f1 !important;
|
||||
box-shadow: -5px 0 20px rgba(0, 0, 0, 0.1);
|
||||
min-height: 100vh;
|
||||
padding: 75px 30px 80px 30px !important;
|
||||
padding: 30px !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
@ -214,8 +188,6 @@ body {
|
||||
height: 50px;
|
||||
transition: margin-left 0.3s ease;
|
||||
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.2);
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.content-header {
|
||||
@ -268,31 +240,21 @@ body {
|
||||
============================================ */
|
||||
.main-sidebar {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: calc(100vh - 50px);
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
z-index: 810;
|
||||
width: 230px;
|
||||
background: #2c3e50 !important;
|
||||
transition: width 0.3s ease;
|
||||
box-shadow: 2px 0 20px rgba(0, 0, 0, 0.3);
|
||||
padding-top: 0 !important;
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
.main-sidebar .logo {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Logo */
|
||||
.logo {
|
||||
flex-shrink: 0;
|
||||
width: 230px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 15px;
|
||||
display: block;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
background: #3498db !important;
|
||||
color: white;
|
||||
@ -300,11 +262,8 @@ body {
|
||||
font-weight: 700;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
transition: width 0.3s ease, padding 0.3s ease;
|
||||
}
|
||||
|
||||
.main-header .navbar {
|
||||
flex: 1;
|
||||
transition: padding 0.3s ease;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.logo-mini {
|
||||
@ -737,7 +696,7 @@ body {
|
||||
left: 230px;
|
||||
margin-left: 2px;
|
||||
right: 0;
|
||||
z-index: 800;
|
||||
z-index: 1000;
|
||||
background: #ffffff !important;
|
||||
padding: 12px 20px;
|
||||
border-top: 2px solid #3498db;
|
||||
@ -754,30 +713,20 @@ body {
|
||||
============================================ */
|
||||
.sidebar-toggle {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 230px;
|
||||
height: 50px;
|
||||
line-height: 30px;
|
||||
z-index: 2000;
|
||||
background: transparent;
|
||||
background: #3c8dbc;
|
||||
color: #fff;
|
||||
padding: 0 15px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: left 0.3s ease;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .sidebar-toggle {
|
||||
left: 70px;
|
||||
}
|
||||
|
||||
.sidebar-toggle::before {
|
||||
content: "\f0c9";
|
||||
font-family: FontAwesome;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
NOTIFICATIONS - Badge modernisé
|
||||
============================================ */
|
||||
@ -842,55 +791,9 @@ body {
|
||||
.sidebar-collapsed .main-sidebar {
|
||||
width: 70px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
direction: rtl;
|
||||
transition: width 0.35s ease;
|
||||
}
|
||||
|
||||
/* Ouvrir la sidebar au survol */
|
||||
.sidebar-collapsed .main-sidebar:hover {
|
||||
width: 230px;
|
||||
overflow-x: visible;
|
||||
direction: rtl;
|
||||
}
|
||||
.sidebar-collapsed .main-sidebar:hover .sidebar-menu > li > a > span {
|
||||
opacity: 1;
|
||||
max-width: 180px;
|
||||
white-space: nowrap;
|
||||
transition: opacity 0.2s ease 0.15s, max-width 0.35s ease;
|
||||
}
|
||||
.sidebar-collapsed .main-sidebar:hover .sidebar-menu > li > a .pull-right-container {
|
||||
opacity: 1;
|
||||
max-width: 20px;
|
||||
transition: opacity 0.2s ease 0.15s, max-width 0.35s ease;
|
||||
}
|
||||
.sidebar-collapsed .main-sidebar:hover .sidebar-menu > li > a {
|
||||
text-align: left;
|
||||
padding: 12px 15px;
|
||||
width: auto;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.sidebar-collapsed .main-sidebar:hover .sidebar-menu i {
|
||||
margin-right: 10px;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
}
|
||||
.sidebar-collapsed .main-sidebar:hover .logo {
|
||||
width: 230px;
|
||||
padding: 15px;
|
||||
}
|
||||
.sidebar-collapsed .main-sidebar:hover .logo-mini {
|
||||
display: none !important;
|
||||
opacity: 0;
|
||||
max-width: 0;
|
||||
}
|
||||
.sidebar-collapsed .main-sidebar:hover .logo-lg {
|
||||
display: inline !important;
|
||||
opacity: 1 !important;
|
||||
max-width: 200px !important;
|
||||
overflow: visible !important;
|
||||
transition: opacity 0.25s ease 0.15s, max-width 0.35s ease;
|
||||
}
|
||||
/* Sous-menus gérés plus bas */
|
||||
|
||||
.sidebar-collapsed .main-sidebar .sidebar-menu {
|
||||
direction: ltr;
|
||||
@ -898,13 +801,6 @@ body {
|
||||
|
||||
.sidebar-collapsed .content-wrapper {
|
||||
margin-left: 70px;
|
||||
width: calc(100% - 70px);
|
||||
}
|
||||
|
||||
.sidebar-collapsed .main-sidebar:hover ~ .content-wrapper {
|
||||
margin-left: 230px;
|
||||
width: calc(100% - 230px);
|
||||
transition: margin-left 0.35s ease, width 0.35s ease;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .main-header {
|
||||
@ -917,35 +813,11 @@ body {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .main-sidebar:hover ~ .main-footer {
|
||||
left: 230px;
|
||||
transition: left 0.35s ease;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .sidebar-toggle {
|
||||
left: 70px;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .main-header .logo {
|
||||
width: 70px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .main-header .logo-mini {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .main-header .logo-lg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logo-mini img {
|
||||
max-height: 40px;
|
||||
max-width: 50px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .main-sidebar .logo {
|
||||
.sidebar-collapsed .logo {
|
||||
padding: 15px 5px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
@ -955,37 +827,22 @@ body {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .main-sidebar .logo-mini {
|
||||
.sidebar-collapsed .logo-mini {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
opacity: 1;
|
||||
max-width: 60px;
|
||||
overflow: hidden;
|
||||
transition: opacity 0.25s ease 0.1s, max-width 0.35s ease;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .main-sidebar .logo-lg {
|
||||
opacity: 0;
|
||||
max-width: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
transition: opacity 0.25s ease, max-width 0.35s ease;
|
||||
.sidebar-collapsed .logo-lg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .sidebar-menu > li > a > span {
|
||||
opacity: 0;
|
||||
max-width: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
transition: opacity 0.2s ease, max-width 0.35s ease;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .sidebar-menu > li > a .pull-right-container {
|
||||
opacity: 0;
|
||||
max-width: 0;
|
||||
overflow: hidden;
|
||||
transition: opacity 0.2s ease, max-width 0.35s ease;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .sidebar-menu > li > a {
|
||||
@ -997,17 +854,7 @@ body {
|
||||
justify-content: center;
|
||||
width: 70px;
|
||||
box-sizing: border-box;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .sidebar-menu > li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .sidebar-menu > li.treeview > .treeview-menu {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin: 5px auto;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .sidebar-menu i {
|
||||
@ -1018,31 +865,114 @@ body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Pas de tooltip en mode réduit */
|
||||
.sidebar-collapsed .sidebar-menu > li > a::before {
|
||||
display: none;
|
||||
content: attr(data-tooltip);
|
||||
position: absolute;
|
||||
left: 70px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: #3498db;
|
||||
color: #fff;
|
||||
padding: 10px 15px;
|
||||
border-radius: 8px;
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 9998;
|
||||
font-size: 14px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
font-weight: 600;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Sidebar hover ouverte : sous-menus par clic (jQuery gère display) */
|
||||
.sidebar-collapsed .main-sidebar:hover .treeview-menu {
|
||||
position: static !important;
|
||||
width: auto !important;
|
||||
background: rgba(0,0,0,0.15) !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
.sidebar-collapsed .sidebar-menu > li:hover > a::before {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
left: 80px;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .treeview-menu {
|
||||
position: fixed;
|
||||
left: 80px;
|
||||
top: auto;
|
||||
width: 200px;
|
||||
max-width: calc(100vw - 100px);
|
||||
z-index: 9999;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.25);
|
||||
border-radius: 4px;
|
||||
border-left: 2px solid #3c8dbc;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s ease;
|
||||
display: block !important;
|
||||
background: #fff;
|
||||
backdrop-filter: blur(8px);
|
||||
border: 1px solid rgba(210, 214, 222, 0.8);
|
||||
pointer-events: none;
|
||||
transform: translateX(-20px) scale(0.95);
|
||||
transform-origin: left center;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .treeview:hover .treeview-menu {
|
||||
pointer-events: auto !important;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translateX(0) scale(1);
|
||||
}
|
||||
|
||||
.sidebar-collapsed .treeview-menu:hover {
|
||||
opacity: 1 !important;
|
||||
visibility: visible !important;
|
||||
transform: none !important;
|
||||
pointer-events: auto !important;
|
||||
transform: translateX(0) scale(1) !important;
|
||||
}
|
||||
.sidebar-collapsed .main-sidebar:hover .treeview-menu > li > a {
|
||||
padding: 8px 15px 8px 30px;
|
||||
color: #b8c7ce;
|
||||
|
||||
.sidebar-collapsed .treeview-menu > li > a {
|
||||
padding: 8px 12px;
|
||||
color: #495057;
|
||||
white-space: nowrap;
|
||||
border-bottom: 1px solid rgba(210, 214, 222, 0.4);
|
||||
transition: all 0.3s ease;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
pointer-events: auto !important;
|
||||
z-index: 10000;
|
||||
}
|
||||
.sidebar-collapsed .main-sidebar:hover .treeview-menu > li > a:hover {
|
||||
|
||||
.sidebar-collapsed .treeview-menu > li:last-child > a {
|
||||
border-bottom: none;
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .treeview-menu > li:first-child > a {
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .treeview-menu > li > a:hover {
|
||||
background: #3c8dbc;
|
||||
color: #fff;
|
||||
background: rgba(255,255,255,0.1);
|
||||
padding-left: 15px;
|
||||
transform: translateX(2px);
|
||||
}
|
||||
|
||||
.sidebar-collapsed .treeview-menu > li > a i {
|
||||
margin-right: 6px;
|
||||
width: 14px;
|
||||
text-align: center;
|
||||
font-size: 11px;
|
||||
opacity: 0.7;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .treeview-menu > li > a:hover i {
|
||||
opacity: 1;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
@ -1237,6 +1167,11 @@ body {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
/* Treeview menu sur mobile */
|
||||
.sidebar-collapsed .treeview-menu {
|
||||
left: 70px;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
/* Charts containers */
|
||||
.col-lg-6[style*="background-color: white"] {
|
||||
@ -1628,7 +1563,9 @@ body {
|
||||
.small-box:nth-child(4) { animation-delay: 0.4s; }
|
||||
.small-box:nth-child(5) { animation-delay: 0.5s; }
|
||||
|
||||
/* animation removed - using click-based submenus */
|
||||
.sidebar-collapsed .treeview:hover .treeview-menu {
|
||||
animation: slideInFromSidebar 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* Désactiver les animations sur mobile pour de meilleures performances */
|
||||
@media (max-width: 768px) {
|
||||
@ -1641,16 +1578,6 @@ body {
|
||||
* {
|
||||
transition-duration: 0.2s !important;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
.info-box-number {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.description-header {
|
||||
font-size: 24px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobiles et petites tablettes (max-width: 768px) */
|
||||
|
||||
@ -1,23 +1,25 @@
|
||||
<header class="main-header">
|
||||
<!-- Logo -->
|
||||
<a href="#" class="logo">
|
||||
<span class="logo-mini"><b><?php if (!empty($company_logo)): ?><img src="<?= base_url($company_logo) ?>?v=<?= time() ?>"><?php else: ?><img src="<?= base_url('assets/images/company_logo.jpg') ?>?v=<?= time() ?>" style="opacity:0.4;"><?php endif; ?></b></span>
|
||||
<span class="logo-lg"><b><?= $company_name ?? 'MotorBike' ?></b></span>
|
||||
<span class="logo-mini"><b><img src="<?= base_url('assets/images/company_logo.jpg') ?>"></b></span>
|
||||
<span class="logo-lg"><b>MotorBike</b></span>
|
||||
</a>
|
||||
|
||||
<!-- Header Navbar -->
|
||||
<nav class="navbar navbar-static-top" style="position: relative; height: 50px; background: #3c8dbc;">
|
||||
<!-- Sidebar toggle button -->
|
||||
<a href="#" class="sidebar-toggle" onclick="toggleSidebar()"></a>
|
||||
<a href="#" class="sidebar-toggle" onclick="toggleSidebar()">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
</a>
|
||||
|
||||
<!-- Navbar Right Menu -->
|
||||
<ul class="navbar-nav" style="position: absolute; right: 15px; top: 50%; transform: translateY(-50%); margin: 0; padding: 0; list-style: none; display: flex; align-items: center; gap: 20px;">
|
||||
|
||||
<!-- Notifications -->
|
||||
<li class="nav-item" style="position: relative;">
|
||||
<i class="fa fa-bell" id="notificationIcon" style="font-size: 20px; cursor: pointer; color:white;" onclick="toggleNotifPanel()"></i>
|
||||
<li class="nav-item dropdown" style="position: relative;">
|
||||
<i class="fa fa-bell" id="notificationIcon" style="font-size: 20px; cursor: pointer; color:white;" data-toggle="dropdown"></i>
|
||||
<span id="notificationCount" class="navbar-badge"></span>
|
||||
<div id="notifPanel" class="notif-dropdown" style="display:none; position:absolute; right:0; top:35px; z-index:9999;">
|
||||
<div class="dropdown-menu dropdown-menu-right notif-dropdown">
|
||||
<div class="notif-panel-header">
|
||||
<span class="notif-panel-title" id="notificationHeader">
|
||||
<i class="fa fa-bell"></i> Notifications
|
||||
@ -76,7 +78,7 @@
|
||||
width: 420px;
|
||||
padding: 0;
|
||||
max-height: 520px;
|
||||
display: flex;
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
@ -84,6 +86,12 @@
|
||||
border: 1px solid rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
/* Afficher quand ouvert (Bootstrap 3: .open, Bootstrap 4: .show) */
|
||||
.open > .notif-dropdown,
|
||||
.notif-dropdown.show {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Header du panel */
|
||||
.notif-panel-header {
|
||||
display: flex;
|
||||
@ -124,7 +132,6 @@
|
||||
#notificationList {
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
max-height: 460px;
|
||||
padding: 8px;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
@ -233,21 +240,6 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function toggleNotifPanel() {
|
||||
var panel = document.getElementById('notifPanel');
|
||||
panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
|
||||
}
|
||||
|
||||
// Fermer le panel en cliquant en dehors
|
||||
document.addEventListener('click', function(e) {
|
||||
var panel = document.getElementById('notifPanel');
|
||||
var icon = document.getElementById('notificationIcon');
|
||||
var badge = document.getElementById('notificationCount');
|
||||
if (panel.style.display === 'block' && !panel.contains(e.target) && e.target !== icon && e.target !== badge) {
|
||||
panel.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
function fetchNotifications() {
|
||||
$.ajax({
|
||||
url: '/notifications',
|
||||
@ -373,47 +365,4 @@ $(document).on('click', '#markAllAsReadBtn', function(e) {
|
||||
|
||||
setInterval(fetchNotifications, 10000);
|
||||
fetchNotifications();
|
||||
|
||||
function showMotoDetails(btn) {
|
||||
var data = JSON.parse(btn.getAttribute('data-moto'));
|
||||
document.getElementById('motoModalName').textContent = data.name || '-';
|
||||
document.getElementById('motoModalSku').textContent = data.sku || '-';
|
||||
document.getElementById('motoModalMoteur').textContent = data.moteur || '-';
|
||||
document.getElementById('motoModalChasis').textContent = data.chasis || '-';
|
||||
document.getElementById('motoModalPuissance').textContent= data.puissance || '-';
|
||||
var imgEl = document.getElementById('motoModalImg');
|
||||
if (data.image) {
|
||||
imgEl.src = data.image;
|
||||
imgEl.style.display = 'block';
|
||||
} else {
|
||||
imgEl.style.display = 'none';
|
||||
}
|
||||
$('#motoDetailModal').modal('show');
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Modal détails moto -->
|
||||
<div class="modal fade" id="motoDetailModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" style="background:#3c8dbc;color:#fff;">
|
||||
<button type="button" class="close" data-dismiss="modal" style="color:#fff;opacity:1;">×</button>
|
||||
<h4 class="modal-title"><i class="fa fa-motorcycle"></i> Détails de la moto</h4>
|
||||
</div>
|
||||
<div class="modal-body" style="text-align:center;">
|
||||
<img id="motoModalImg" src="" alt="Photo moto"
|
||||
style="max-width:100%;max-height:250px;object-fit:contain;border-radius:8px;margin-bottom:16px;border:1px solid #eee;">
|
||||
<table class="table table-bordered table-condensed" style="text-align:left;margin-top:10px;">
|
||||
<tr><th style="width:40%">Modèle</th><td id="motoModalName"></td></tr>
|
||||
<tr><th>N° Série</th><td id="motoModalSku"></td></tr>
|
||||
<tr><th>N° Moteur</th><td id="motoModalMoteur"></td></tr>
|
||||
<tr><th>Châssis</th><td id="motoModalChasis"></td></tr>
|
||||
<tr><th>Puissance</th><td id="motoModalPuissance"></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Fermer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -273,6 +273,7 @@
|
||||
<li id="reportNav">
|
||||
<a href="<?php echo base_url('reports/') ?>">
|
||||
<i class="glyphicon glyphicon-stats"></i> <span>Rapports</span>
|
||||
<span class="tooltip">Rapports</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
@ -285,18 +286,6 @@
|
||||
</li>
|
||||
<?php endif; ?> -->
|
||||
|
||||
<?php
|
||||
$session = session();
|
||||
$currentUser = $session->get('user');
|
||||
if (isset($currentUser['group_name']) && $currentUser['group_name'] === 'SuperAdmin'):
|
||||
?>
|
||||
<li id="mainActionLogNav">
|
||||
<a href="<?php echo base_url('action-log') ?>">
|
||||
<i class="fa fa-history"></i> <span>Historique des Actions</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (in_array('updateCompany', $user_permission)): ?>
|
||||
<li id="companyNav"><a href="<?php echo base_url('company/') ?>"><i class="fa fa-building"></i> <span>Entreprise</span></a></li>
|
||||
<?php endif; ?>
|
||||
|
||||
@ -53,7 +53,9 @@
|
||||
<th>Phone</th>
|
||||
<th>Point de vente</th>
|
||||
<th>Role</th>
|
||||
<?php if (in_array('updateUser', $user_permission) || in_array('deleteUser', $user_permission)): ?>
|
||||
<th>Action</th>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user