Compare commits
6 Commits
feat/notif
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| e02671e860 | |||
| 38d37a0987 | |||
| fe80b9c4f8 | |||
| a195d24e78 | |||
|
|
a18ccbf34b | ||
| 83374f96c3 |
@ -22,7 +22,6 @@ use App\Controllers\ReservationController;
|
|||||||
use App\Controllers\SecuriteController;
|
use App\Controllers\SecuriteController;
|
||||||
use App\Controllers\SortieCaisseController;
|
use App\Controllers\SortieCaisseController;
|
||||||
use App\Controllers\RemiseController;
|
use App\Controllers\RemiseController;
|
||||||
use App\Controllers\PerformanceController;
|
|
||||||
/**
|
/**
|
||||||
* auth route
|
* auth route
|
||||||
* the option array filter make a filter,
|
* the option array filter make a filter,
|
||||||
@ -50,6 +49,7 @@ $routes->group('', ['filter' => 'auth'], function ($routes) {
|
|||||||
* dashboard route
|
* dashboard route
|
||||||
*/
|
*/
|
||||||
$routes->get('/', [Dashboard::class, 'index']);
|
$routes->get('/', [Dashboard::class, 'index']);
|
||||||
|
$routes->get('/dashboard/getTresorerieData', [Dashboard::class, 'getTresorerieData']);
|
||||||
$routes->get('/ventes', [Auth::class, 'ventes']);
|
$routes->get('/ventes', [Auth::class, 'ventes']);
|
||||||
$routes->get('/ventes/(:num)', [Auth::class, 'addImage']);
|
$routes->get('/ventes/(:num)', [Auth::class, 'addImage']);
|
||||||
$routes->get('/ventes/fetchProductVente/(:num)', [Auth::class, 'fetchProductVente']);
|
$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->get('update/(:num)', [ProductCOntroller::class, 'update']);
|
||||||
$routes->post('update/(:num)', [ProductCOntroller::class, 'update']);
|
$routes->post('update/(:num)', [ProductCOntroller::class, 'update']);
|
||||||
$routes->post('remove', [ProductCOntroller::class, 'remove']);
|
$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('assign_store', [ProductCOntroller::class, 'assign_store']);
|
||||||
$routes->post('createByExcel', [ProductCOntroller::class, 'createByExcel']);
|
$routes->post('createByExcel', [ProductCOntroller::class, 'createByExcel']);
|
||||||
$routes->post('checkProductAvailability', [ProductCOntroller::class, 'checkProductAvailability']);
|
$routes->post('checkProductAvailability', [ProductCOntroller::class, 'checkProductAvailability']);
|
||||||
@ -226,7 +226,7 @@ $routes->group('', ['filter' => 'auth'], function ($routes) {
|
|||||||
$routes->get('detail/stock', [ReportController::class, 'stockDetail']);
|
$routes->get('detail/stock', [ReportController::class, 'stockDetail']);
|
||||||
|
|
||||||
// Corrections fetct → fetch
|
// Corrections fetct → fetch
|
||||||
$routes->get('detail/fetchData/(:num)', [ReportController::class, 'fetchProductSold/$1']);
|
$routes->get('detail/fetchData/(:num)', [ReportController::class, 'fetchProductSodled/$1']);
|
||||||
$routes->get('detail/fetchDataStock/(:num)', [ReportController::class, 'fetchProductStock/$1']);
|
$routes->get('detail/fetchDataStock/(:num)', [ReportController::class, 'fetchProductStock/$1']);
|
||||||
$routes->get('detail/fetchDataStock2/(:num)', [ReportController::class, 'fetchProductStock2/$1']);
|
$routes->get('detail/fetchDataStock2/(:num)', [ReportController::class, 'fetchProductStock2/$1']);
|
||||||
|
|
||||||
@ -389,6 +389,13 @@ $routes->group('avances', function ($routes) {
|
|||||||
$routes->post('validateAvance', [AvanceController::class, 'validateAvance']);
|
$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
|
// historique
|
||||||
$routes->group('historique', ['filter' => 'auth'], static function ($routes) {
|
$routes->group('historique', ['filter' => 'auth'], static function ($routes) {
|
||||||
$routes->get('/', 'HistoriqueController::index');
|
$routes->get('/', 'HistoriqueController::index');
|
||||||
|
|||||||
@ -59,4 +59,6 @@ class View extends BaseView
|
|||||||
* @var list<class-string<ViewDecoratorInterface>>
|
* @var list<class-string<ViewDecoratorInterface>>
|
||||||
*/
|
*/
|
||||||
public array $decorators = [];
|
public array $decorators = [];
|
||||||
|
|
||||||
|
public string $appOverridesFolder = APPPATH . 'Views/';
|
||||||
}
|
}
|
||||||
|
|||||||
154
app/Controllers/ActionLogController.php
Normal file
154
app/Controllers/ActionLogController.php
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,7 +24,7 @@ abstract class AdminController extends BaseController
|
|||||||
$group_data = $Groups->getUserGroupByUserId($userId);
|
$group_data = $Groups->getUserGroupByUserId($userId);
|
||||||
|
|
||||||
$this->permission = unserialize($group_data['permission']);
|
$this->permission = unserialize($group_data['permission']);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,6 +44,13 @@ abstract class AdminController extends BaseController
|
|||||||
protected function render_template($page = null, $data = [])
|
protected function render_template($page = null, $data = [])
|
||||||
{
|
{
|
||||||
$data['user_permission'] = $this->permission;
|
$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', $data);
|
||||||
echo view('templates/header_menu', $data);
|
echo view('templates/header_menu', $data);
|
||||||
echo view('templates/side_menubar', $data);
|
echo view('templates/side_menubar', $data);
|
||||||
@ -51,6 +58,14 @@ abstract class AdminController extends BaseController
|
|||||||
echo view('templates/footer', $data);
|
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
|
// Get company currency using model
|
||||||
public function company_currency()
|
public function company_currency()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use App\Models\ProductImage;
|
|||||||
use App\Models\Users;
|
use App\Models\Users;
|
||||||
use App\Models\Stores;
|
use App\Models\Stores;
|
||||||
use App\Models\Products;
|
use App\Models\Products;
|
||||||
|
use App\Models\Historique;
|
||||||
|
|
||||||
class Auth extends AdminController
|
class Auth extends AdminController
|
||||||
{
|
{
|
||||||
@ -79,6 +80,10 @@ public function loginPost()
|
|||||||
'logged_in' => true
|
'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
|
// Redirect to dashboard
|
||||||
return redirect()->to('/');
|
return redirect()->to('/');
|
||||||
}
|
}
|
||||||
@ -124,7 +129,8 @@ public function loginPost()
|
|||||||
$buttons .= " <a href='/ventes/show/" . $value['id'] . "' class='btn btn-default'><i class='fa fa-eye'></i></a>";
|
$buttons .= " <a href='/ventes/show/" . $value['id'] . "' class='btn btn-default'><i class='fa fa-eye'></i></a>";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($this->permission) && in_array('createOrder', $this->permission)) {
|
$productSoldStatus = (int)($value['product_sold'] ?? 0);
|
||||||
|
if (is_array($this->permission) && in_array('createOrder', $this->permission) && $productSoldStatus === 0) {
|
||||||
$buttons .= ($value['qty'] == 1)
|
$buttons .= ($value['qty'] == 1)
|
||||||
? " <a href='/orders/createFromEspace/" . $value['id'] . "' class='btn btn-default'><i class='fa fa-shopping-cart'></i></a>"
|
? " <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>";
|
: " <button class='btn btn-default' title='0 en stock'><i class='fa fa-shopping-cart'></i></button>";
|
||||||
@ -134,6 +140,16 @@ public function loginPost()
|
|||||||
|
|
||||||
$img = '<img src="' . base_url('assets/images/product_image/' . $value['image']) . '" alt="' . $value['image'] . '" class="img-circle" width="50" height="50" />';
|
$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
|
// Populate the result data
|
||||||
$result['data'][] = [
|
$result['data'][] = [
|
||||||
$img,
|
$img,
|
||||||
@ -142,6 +158,7 @@ public function loginPost()
|
|||||||
number_format($value['prix_vente'], 0, ',', ' '),
|
number_format($value['prix_vente'], 0, ',', ' '),
|
||||||
$value['puissance'] . ' CC',
|
$value['puissance'] . ' CC',
|
||||||
$value['numero_de_moteur'],
|
$value['numero_de_moteur'],
|
||||||
|
$statut,
|
||||||
$buttons
|
$buttons
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ namespace App\Controllers;
|
|||||||
use App\Models\AutresEncaissements;
|
use App\Models\AutresEncaissements;
|
||||||
use App\Models\Stores;
|
use App\Models\Stores;
|
||||||
use App\Models\Users;
|
use App\Models\Users;
|
||||||
|
use App\Models\Historique;
|
||||||
|
|
||||||
class AutresEncaissementsController extends AdminController
|
class AutresEncaissementsController extends AdminController
|
||||||
{
|
{
|
||||||
@ -41,7 +42,7 @@ class AutresEncaissementsController extends AdminController
|
|||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
if ($this->request->getMethod() !== 'post') {
|
if (strtolower($this->request->getMethod()) !== 'post') {
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'messages' => 'Méthode non autorisée'
|
'messages' => 'Méthode non autorisée'
|
||||||
@ -103,36 +104,14 @@ class AutresEncaissementsController extends AdminController
|
|||||||
$notificationMessage = "Nouvel encaissement {$finalType} créé par {$user['firstname']} {$user['lastname']} - Montant: {$montantFormate} Ar";
|
$notificationMessage = "Nouvel encaissement {$finalType} créé par {$user['firstname']} {$user['lastname']} - Montant: {$montantFormate} Ar";
|
||||||
|
|
||||||
// ✅ Envoyer notification à DAF, Direction et SuperAdmin de TOUS les stores
|
// ✅ Envoyer notification à DAF, Direction et SuperAdmin de TOUS les stores
|
||||||
foreach ($allStores as $store) {
|
$Notification->notifyGroupsByPermissionAllStores('notifEncaissement', $notificationMessage, 'encaissements');
|
||||||
$storeId = (int)$store['id'];
|
|
||||||
|
log_message('info', "✅ Encaissement {$encaissementId} créé - Notifications envoyées");
|
||||||
// Notification pour DAF
|
|
||||||
$Notification->createNotification(
|
// Log de l'action
|
||||||
$notificationMessage,
|
$historique = new Historique();
|
||||||
"DAF",
|
$historique->logAction('autres_encaissements', 'CREATE', $encaissementId, "Encaissement {$finalType} - Montant: {$montantFormate} Ar");
|
||||||
$storeId,
|
|
||||||
'encaissements'
|
|
||||||
);
|
|
||||||
|
|
||||||
// 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([
|
return $this->response->setJSON([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'messages' => 'Encaissement enregistré avec succès'
|
'messages' => 'Encaissement enregistré avec succès'
|
||||||
@ -204,31 +183,8 @@ class AutresEncaissementsController extends AdminController
|
|||||||
|
|
||||||
$notificationMessage = "Encaissement {$finalType} modifié par {$user['firstname']} {$user['lastname']} - Ancien montant: {$ancienMontant} Ar → Nouveau: {$montantFormate} Ar";
|
$notificationMessage = "Encaissement {$finalType} modifié par {$user['firstname']} {$user['lastname']} - Ancien montant: {$ancienMontant} Ar → Nouveau: {$montantFormate} Ar";
|
||||||
|
|
||||||
foreach ($allStores as $store) {
|
$Notification->notifyGroupsByPermissionAllStores('notifEncaissement', $notificationMessage, 'encaissements');
|
||||||
$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");
|
log_message('info', "✅ Encaissement {$id} modifié - Notifications envoyées");
|
||||||
|
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
@ -287,31 +243,8 @@ class AutresEncaissementsController extends AdminController
|
|||||||
|
|
||||||
$notificationMessage = "⚠️ Encaissement {$type} supprimé par {$user['firstname']} {$user['lastname']} - Montant: {$montantFormate} Ar";
|
$notificationMessage = "⚠️ Encaissement {$type} supprimé par {$user['firstname']} {$user['lastname']} - Montant: {$montantFormate} Ar";
|
||||||
|
|
||||||
foreach ($allStores as $store) {
|
$Notification->notifyGroupsByPermissionAllStores('notifEncaissement', $notificationMessage, 'encaissements');
|
||||||
$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");
|
log_message('info', "✅ Encaissement {$id} supprimé - Notifications envoyées");
|
||||||
|
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
|
|||||||
@ -116,21 +116,23 @@ private function buildDataRow($value, $product, $isAdmin, $isCommerciale, $isCai
|
|||||||
{
|
{
|
||||||
$date_time = date('d-m-Y h:i a', strtotime($value['avance_date']));
|
$date_time = date('d-m-Y h:i a', strtotime($value['avance_date']));
|
||||||
|
|
||||||
// ✅ Gestion sécurisée du nom du produit
|
// Gestion du nom du produit et numéro de série
|
||||||
|
$productSku = '';
|
||||||
if ($value['type_avance'] === 'mere') {
|
if ($value['type_avance'] === 'mere') {
|
||||||
$productName = $value['product_name'] ?? 'Produit sur mer';
|
$productName = $value['product_name'] ?? 'Produit sur mer';
|
||||||
} else {
|
} else {
|
||||||
$productName = !empty($value['product_name'])
|
$productData = !empty($value['product_id']) ? $product->find($value['product_id']) : null;
|
||||||
? $value['product_name']
|
$productName = $productData['name'] ?? ($value['product_name'] ?? 'N/A');
|
||||||
: $product->getProductNameById($value['product_id'] ?? 0);
|
$productSku = $productData['sku'] ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($isAdmin) {
|
if ($isAdmin) {
|
||||||
return [
|
return [
|
||||||
$value['customer_name'],
|
$value['customer_name'],
|
||||||
$value['customer_phone'],
|
$value['customer_phone'],
|
||||||
$value['customer_address'],
|
$value['customer_address'],
|
||||||
$productName,
|
$productName,
|
||||||
|
$productSku,
|
||||||
number_format((int)$value['gross_amount'], 0, ',', ' '),
|
number_format((int)$value['gross_amount'], 0, ',', ' '),
|
||||||
number_format((int)$value['avance_amount'], 0, ',', ' '),
|
number_format((int)$value['avance_amount'], 0, ',', ' '),
|
||||||
number_format((int)$value['amount_due'], 0, ',', ' '),
|
number_format((int)$value['amount_due'], 0, ',', ' '),
|
||||||
@ -141,6 +143,7 @@ private function buildDataRow($value, $product, $isAdmin, $isCommerciale, $isCai
|
|||||||
return [
|
return [
|
||||||
$value['avance_id'],
|
$value['avance_id'],
|
||||||
$productName,
|
$productName,
|
||||||
|
$productSku,
|
||||||
number_format((int)$value['avance_amount'], 0, ',', ' '),
|
number_format((int)$value['avance_amount'], 0, ',', ' '),
|
||||||
number_format((int)$value['amount_due'], 0, ',', ' '),
|
number_format((int)$value['amount_due'], 0, ',', ' '),
|
||||||
$date_time,
|
$date_time,
|
||||||
@ -195,7 +198,75 @@ private function fetchAvanceDataGeneric($methodName = 'getAllAvanceData')
|
|||||||
|
|
||||||
public function fetchAvanceBecameOrder()
|
public function fetchAvanceBecameOrder()
|
||||||
{
|
{
|
||||||
return $this->fetchAvanceDataGeneric('getCompletedAvances');
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fetchExpiredAvance()
|
public function fetchExpiredAvance()
|
||||||
@ -318,28 +389,11 @@ public function validateAvance()
|
|||||||
$customerName = $avance['customer_name'];
|
$customerName = $avance['customer_name'];
|
||||||
$avanceNumber = str_pad($avance['avance_id'], 5, '0', STR_PAD_LEFT);
|
$avanceNumber = str_pad($avance['avance_id'], 5, '0', STR_PAD_LEFT);
|
||||||
|
|
||||||
// Notifier le commercial
|
// Notifier les commerciaux
|
||||||
$Notification->createNotification(
|
$Notification->notifyGroupsByPermission('notifRemise', "✅ Votre avance N°{$avanceNumber} pour le client {$customerName} a été validée par la caissière", (int)$users['store_id'], 'avances');
|
||||||
"✅ Votre avance N°{$avanceNumber} pour le client {$customerName} a été validée par la caissière",
|
|
||||||
"COMMERCIALE",
|
// Notifier les groupes ayant updateAvance
|
||||||
(int)$users['store_id'],
|
$Notification->notifyGroupsByPermission('notifAvance', "La caissière a validé l'avance N°{$avanceNumber} créée par un commercial", (int)$users['store_id'], 'avances');
|
||||||
'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([
|
return $this->response->setJSON([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
@ -565,7 +619,7 @@ public function validateAvance()
|
|||||||
{
|
{
|
||||||
$this->verifyRole('createAvance');
|
$this->verifyRole('createAvance');
|
||||||
|
|
||||||
if ($this->request->getMethod() !== 'post') {
|
if (strtolower($this->request->getMethod()) !== 'post') {
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'messages' => 'Méthode non autorisée'
|
'messages' => 'Méthode non autorisée'
|
||||||
@ -672,43 +726,12 @@ public function validateAvance()
|
|||||||
|
|
||||||
$notificationMessage = "Nouvelle avance {$typeAvanceLabel} créée par {$users['firstname']} {$users['lastname']} - Client: {$customerName} - Montant: {$avanceAmount} Ar";
|
$notificationMessage = "Nouvelle avance {$typeAvanceLabel} créée par {$users['firstname']} {$users['lastname']} - Client: {$customerName} - Montant: {$avanceAmount} Ar";
|
||||||
|
|
||||||
// ✅ Envoyer notification à DAF, Direction et SuperAdmin de TOUS les stores
|
// ✅ Notifier tous les groupes ayant updateAvance de TOUS les stores
|
||||||
foreach ($allStores as $store) {
|
$Notification->notifyGroupsByPermissionAllStores('notifAvance', $notificationMessage, 'avances');
|
||||||
$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)
|
// ✅ Notification à la Caissière UNIQUEMENT du store concerné (si l'utilisateur est COMMERCIALE)
|
||||||
if ($this->isCommerciale($users)) {
|
if ($this->isCommerciale($users)) {
|
||||||
$Notification->createNotification(
|
$Notification->notifyGroupsByPermission('notifSortieCaisse', 'Une nouvelle avance a été créée par un commercial', (int)$users['store_id'], 'avances');
|
||||||
'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");
|
log_message('info', "✅ Avance {$avance_id} créée - Notifications envoyées à DAF/Direction/SuperAdmin de tous les stores");
|
||||||
@ -737,7 +760,7 @@ public function validateAvance()
|
|||||||
{
|
{
|
||||||
$this->verifyRole('updateAvance');
|
$this->verifyRole('updateAvance');
|
||||||
|
|
||||||
if ($this->request->getMethod() !== 'post') {
|
if (strtolower($this->request->getMethod()) !== 'post') {
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'messages' => 'Méthode non autorisée'
|
'messages' => 'Méthode non autorisée'
|
||||||
@ -901,12 +924,7 @@ public function validateAvance()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ✅ NOTIFICATION (modification simple)
|
// ✅ NOTIFICATION (modification simple)
|
||||||
$Notification->createNotification(
|
$Notification->notifyGroupsByPermission('notifSortieCaisse', 'Une avance a été modifiée', (int)$users['store_id'], 'avances');
|
||||||
'Une avance a été modifiée',
|
|
||||||
"Caissière",
|
|
||||||
(int)$users['store_id'],
|
|
||||||
'avances'
|
|
||||||
);
|
|
||||||
|
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
@ -1051,24 +1069,29 @@ public function printInvoice($avance_id)
|
|||||||
return redirect()->back()->with('error', 'Accès non autorisé');
|
return redirect()->back()->with('error', 'Accès non autorisé');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ CORRECTION SIMPLIFIÉE
|
// 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 = '';
|
||||||
if ($avance['type_avance'] === 'mere' && !empty($avance['product_name'])) {
|
if ($avance['type_avance'] === 'mere' && !empty($avance['product_name'])) {
|
||||||
$productName = $avance['product_name'];
|
|
||||||
$productDetails = [
|
$productDetails = [
|
||||||
'marque' => $avance['product_name'],
|
'marque' => $avance['product_name'],
|
||||||
'numero_moteur' => '',
|
'numero_moteur' => '',
|
||||||
'puissance' => ''
|
'puissance' => '',
|
||||||
|
'couleur' => '',
|
||||||
|
'chasis' => '',
|
||||||
|
'type_avance' => 'mere',
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
$product = $Products->find($avance['product_id']);
|
$product = $Products->find($avance['product_id']);
|
||||||
|
|
||||||
if (!$product) {
|
if (!$product) {
|
||||||
return redirect()->back()->with('error', 'Produit non trouvé');
|
return redirect()->back()->with('error', 'Produit non trouvé');
|
||||||
}
|
}
|
||||||
|
|
||||||
$productName = $product['name'] ?? 'N/A';
|
|
||||||
|
|
||||||
// ✅ Récupérer le nom de la marque
|
|
||||||
$brandName = 'N/A';
|
$brandName = 'N/A';
|
||||||
if (!empty($product['marque'])) {
|
if (!empty($product['marque'])) {
|
||||||
$db = \Config\Database::connect();
|
$db = \Config\Database::connect();
|
||||||
@ -1081,15 +1104,18 @@ public function printInvoice($avance_id)
|
|||||||
$brandName = $brandResult['name'];
|
$brandName = $brandResult['name'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$productDetails = [
|
$productDetails = [
|
||||||
'marque' => $brandName,
|
'marque' => $brandName,
|
||||||
'numero_moteur' => $product['numero_de_moteur'] ?? '',
|
'numero_moteur' => $product['numero_de_moteur'] ?? '',
|
||||||
'puissance' => $product['puissance'] ?? ''
|
'puissance' => $product['puissance'] ?? '',
|
||||||
|
'couleur' => $product['cler'] ?? '',
|
||||||
|
'chasis' => $product['chasis'] ?? '',
|
||||||
|
'type_avance' => $avance['type_avance'] ?? 'terre',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$html = $this->generatePrintableInvoiceHTML($avance, $productName, $productDetails);
|
$html = $this->generatePrintableInvoiceHTML($avance, $productDetails, $companyData);
|
||||||
|
|
||||||
return $this->response->setBody($html);
|
return $this->response->setBody($html);
|
||||||
|
|
||||||
@ -1756,24 +1782,10 @@ public function notifyPrintInvoice()
|
|||||||
$customerName = $avance['customer_name'];
|
$customerName = $avance['customer_name'];
|
||||||
$avanceNumber = str_pad($avance['avance_id'], 5, '0', STR_PAD_LEFT);
|
$avanceNumber = str_pad($avance['avance_id'], 5, '0', STR_PAD_LEFT);
|
||||||
|
|
||||||
$Notification->createNotification(
|
$Notification->notifyGroupsByPermission(
|
||||||
"La caissière a imprimé la facture N°{$avanceNumber} pour le client {$customerName}",
|
'updateAvance',
|
||||||
"Direction",
|
"La caissière a imprimé la facture avance N°{$avanceNumber} pour le client {$customerName}",
|
||||||
(int)$users['store_id'],
|
(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'
|
'avances'
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1888,27 +1900,42 @@ public function getFullInvoiceForPrint($avance_id)
|
|||||||
/**
|
/**
|
||||||
* Générer le HTML optimisé pour l'impression (version identique à printInvoice)
|
* Générer le HTML optimisé pour l'impression (version identique à printInvoice)
|
||||||
*/
|
*/
|
||||||
private function generatePrintableInvoiceHTML($avance, $productName, $productDetails)
|
private function generatePrintableInvoiceHTML($avance, $productDetails, $companyData)
|
||||||
{
|
{
|
||||||
$avanceDate = date('d/m/Y', strtotime($avance['avance_date']));
|
$avanceDate = date('d/m/Y', strtotime($avance['avance_date']));
|
||||||
$avanceNumber = str_pad($avance['avance_id'], 5, '0', STR_PAD_LEFT);
|
$avanceNumber = str_pad($avance['avance_id'], 5, '0', STR_PAD_LEFT);
|
||||||
$customerName = strtoupper(esc($avance['customer_name']));
|
$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, ',', ' ');
|
$grossAmount = number_format($avance['gross_amount'], 0, ',', ' ');
|
||||||
$avanceAmount = number_format($avance['avance_amount'], 0, ',', ' ');
|
$avanceAmount = number_format($avance['avance_amount'], 0, ',', ' ');
|
||||||
$amountDue = number_format($avance['amount_due'], 0, ',', ' ');
|
$amountDue = number_format($avance['amount_due'], 0, ',', ' ');
|
||||||
$marque = esc($productDetails['marque']) ?: $productName;
|
$marque = esc($productDetails['marque']);
|
||||||
$numeroMoteur = esc($productDetails['numero_moteur']);
|
$numeroMoteur = esc($productDetails['numero_moteur']);
|
||||||
$puissance = esc($productDetails['puissance']);
|
$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
|
return <<<HTML
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Facture Avance - KELY SCOOTERS</title>
|
<title>Facture d'Acompte - {$companyName}</title>
|
||||||
<style>
|
<style>
|
||||||
@media print {
|
@media print {
|
||||||
body { margin: 0; padding: 0; }
|
body { margin: 0; padding: 0; }
|
||||||
@ -1916,281 +1943,352 @@ private function generatePrintableInvoiceHTML($avance, $productName, $productDet
|
|||||||
.page { page-break-after: always; }
|
.page { page-break-after: always; }
|
||||||
.page:last-child { page-break-after: auto; }
|
.page:last-child { page-break-after: auto; }
|
||||||
}
|
}
|
||||||
|
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
font-size: 12px;
|
font-size: 13px;
|
||||||
line-height: 1.4;
|
line-height: 1.6;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
width: 210mm;
|
width: 210mm;
|
||||||
height: 297mm;
|
min-height: 297mm;
|
||||||
padding: 15mm;
|
padding: 15mm 20mm;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
background: white;
|
background: white;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.invoice-container {
|
/* === RECTO === */
|
||||||
border: 2px solid #000;
|
.recto-title {
|
||||||
padding: 20px;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-bottom: 2px solid #000;
|
font-size: 20px;
|
||||||
padding-bottom: 10px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header h1 {
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-bottom: 5px;
|
text-decoration: underline;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
letter-spacing: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-info {
|
.recto-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-top: 10px;
|
align-items: flex-start;
|
||||||
font-size: 11px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-left, .header-right {
|
.recto-company {
|
||||||
text-align: left;
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.invoice-title {
|
.recto-company strong {
|
||||||
display: flex;
|
font-size: 14px;
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin: 15px 0;
|
|
||||||
padding: 10px;
|
|
||||||
border: 1px solid #000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.invoice-title h2 {
|
.recto-date-qr {
|
||||||
font-size: 18px;
|
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);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
letter-spacing: 10px;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.original-badge {
|
.recto-body {
|
||||||
background: #000;
|
position: relative;
|
||||||
color: #fff;
|
z-index: 1;
|
||||||
padding: 5px 15px;
|
|
||||||
font-weight: bold;
|
|
||||||
transform: skewX(-10deg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.customer-info {
|
.field-line {
|
||||||
margin: 15px 0;
|
margin: 12px 0;
|
||||||
padding: 10px;
|
font-size: 13px;
|
||||||
border: 1px solid #000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.customer-info div {
|
.field-line strong {
|
||||||
margin: 5px 0;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
.product-table {
|
.product-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin: 15px 0;
|
margin-top: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-table th, .product-table td {
|
.product-table th, .product-table td {
|
||||||
border: 1px solid #000;
|
border: 2px solid #000;
|
||||||
padding: 8px;
|
padding: 10px 12px;
|
||||||
text-align: left;
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-table th {
|
.product-table th {
|
||||||
background: #f0f0f0;
|
|
||||||
font-weight: bold;
|
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 {
|
.signature-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-top: auto;
|
margin-top: 50px;
|
||||||
padding: 20px 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.signature-box {
|
.signature-box {
|
||||||
text-align: center;
|
width: 40%;
|
||||||
width: 45%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signature-box p {
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style spécifique pour le verso */
|
|
||||||
.contract-section {
|
|
||||||
margin-top: 20px;
|
|
||||||
padding: 15px;
|
|
||||||
border: 2px solid #000;
|
border: 2px solid #000;
|
||||||
font-size: 10px;
|
min-height: 80px;
|
||||||
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contract-section h3 {
|
.signature-box .sig-title {
|
||||||
text-align: center;
|
font-weight: bold;
|
||||||
font-size: 14px;
|
font-size: 13px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 60px;
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contract-article {
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contract-article strong {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.verso-content {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- RECTO -->
|
<!-- ==================== RECTO ==================== -->
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<div class="invoice-container">
|
<div class="watermark">ORIGINAL</div>
|
||||||
<!-- Header -->
|
|
||||||
<div class="header">
|
<div class="recto-title">FACTURE D'ACOMPTE DE RESERVATION</div>
|
||||||
<h1>KELY SCOOTERS</h1>
|
|
||||||
<div class="header-info">
|
<div class="recto-header">
|
||||||
<div class="header-left">
|
<div class="recto-company">
|
||||||
<div>NIF: 401 840 5554</div>
|
<strong>{$companyName}</strong><br>
|
||||||
<div>STAT: 46101 11 2024 00317</div>
|
NIF : {$companyNIF}<br>
|
||||||
</div>
|
STAT : {$companySTAT}<br>
|
||||||
<div class="header-right">
|
Contact : {$companyPhone} / {$companyPhone2}<br>
|
||||||
<div>Contact: +261 34 27 946 35 / +261 34 07 079 69</div>
|
{$companyAddress}
|
||||||
<div>Antsakaviro en face WWF</div>
|
</div>
|
||||||
</div>
|
<div class="recto-date-qr">
|
||||||
|
<div class="date-block">
|
||||||
|
Date : <strong>{$avanceDate}</strong><br>
|
||||||
|
N° : <strong>{$avanceNumber}</strong>
|
||||||
</div>
|
</div>
|
||||||
|
<canvas id="qrcode" class="qr-code"></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Invoice Title -->
|
|
||||||
<div class="invoice-title">
|
<div class="recto-body">
|
||||||
<div>
|
<div class="field-line"><strong>DOIT</strong></div>
|
||||||
<h2>FACTURE</h2>
|
|
||||||
<div>Date: {$avanceDate}</div>
|
<div class="field-line">
|
||||||
<div>N°: {$avanceNumber}CI 2025</div>
|
<strong>NOM :</strong>
|
||||||
</div>
|
<span class="field-value">{$customerName}</span>
|
||||||
<div class="original-badge">DOIT ORIGINAL</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Customer Info -->
|
<div class="field-line">
|
||||||
<div class="customer-info">
|
<strong>N de Série ou Arrivage :</strong>
|
||||||
<div><strong>NOM:</strong> {$customerName} ({$customerPhone})</div>
|
<span class="field-value">{$nSerieOuArrivage}</span>
|
||||||
<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>
|
||||||
|
|
||||||
<!-- Product Table -->
|
<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 -->
|
||||||
<table class="product-table">
|
<table class="product-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>MARQUE</th>
|
<th>MARQUE</th>
|
||||||
<th>N°MOTEUR</th>
|
<th>N° Châssis/Arrivage</th>
|
||||||
<th>PUISSANCE</th>
|
<th>PUISSANCE</th>
|
||||||
<th>RAP (Ariary)</th>
|
<th>Reste à payer (Ariary)</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{$marque}</td>
|
<td>{$marque}</td>
|
||||||
<td>{$numeroMoteur}</td>
|
<td>{$chasis}</td>
|
||||||
<td>{$puissance}</td>
|
<td>{$puissance}</td>
|
||||||
<td>{$amountDue}</td>
|
<td>{$amountDue}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- VERSO -->
|
|
||||||
<div class="page">
|
|
||||||
<div class="invoice-container">
|
|
||||||
|
|
||||||
|
<!-- ==================== VERSO ==================== -->
|
||||||
<div class="invoice-title">
|
<div class="page">
|
||||||
<div>
|
<div class="verso-header">
|
||||||
<h2>CONDITIONS GÉNÉRALES</h2>
|
<strong>{$companyName}</strong><br>
|
||||||
<div>Date: {$avanceDate}</div>
|
NIF : {$companyNIF}<br>
|
||||||
<div>N°: {$avanceNumber}CI 2025</div>
|
STAT : {$companySTAT}<br>
|
||||||
|
Contact : {$companyPhone} / {$companyPhone2}<br>
|
||||||
<div class="verso-content">
|
{$companyAddress}
|
||||||
<!-- Contract Section -->
|
</div>
|
||||||
<div class="contract-section">
|
|
||||||
<h3>FIFANEKENA ARA-BAROTRA (Réservations)</h3>
|
<div class="verso-title">FIFANEKENA ARA-BAROTRA (Reservations)</div>
|
||||||
<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="verso-intro">
|
||||||
|
Ry mpanjifa hajaina,<br><br>
|
||||||
<div class="contract-article">
|
Natao ity fifanekena ity mba hialana amin'ny fivadiahampitokisana amin'ny andaniny sy ankilany.
|
||||||
<strong>Andininy faha-1: FAMANDRAHANA SY FANDOAVAM-BOLA</strong>
|
</div>
|
||||||
<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="article">
|
||||||
|
<div class="article-title">• Andininy faha-1 : FAMANDRIHANA SY FANDOAVAM-BOLA</div>
|
||||||
<div class="contract-article">
|
<p>Ny mpividy dia manao famandrihana amin'ny alalan'ny fandoavam-bola mihoatra ny 25 isan-jato amin'ny vidin'entana rehetra (avances).</p>
|
||||||
<strong>Andininy faha-2: FANDOAVAM-BOLA REHEFA TONGA NY ENTANA (ARRIVAGE)</strong>
|
</div>
|
||||||
<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 class="article">
|
||||||
</div>
|
<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>
|
||||||
<div class="contract-article">
|
<p>Manana 15 andro kosa andoaovana ny 25 isan-jato raha misy tsy fahafahana alohan'ny famoahana ny entana.</p>
|
||||||
<strong>Andininy faha-3: FAMERENANA VOLA</strong>
|
</div>
|
||||||
<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-3 : FAMERENANA VOLA</div>
|
||||||
<div class="contract-article">
|
<p>Raha toa ka misy antony tsy hakana ny entana indray dia tsy mamerina ny vola efa voaloha (avance) ny société.</p>
|
||||||
<strong>Andininy faha-4: FEPETRA FANAMPINY</strong>
|
</div>
|
||||||
<ul style="margin-left: 20px;">
|
|
||||||
<li>Tsy misafidy raha toa ka mamafa no ifanarahana.</li>
|
<div class="article">
|
||||||
<li>Tsy azo atao ny mamerina ny entana efa nofandrahana.</li>
|
<div class="article-title">• Andininy faha-4 : FEPETRA FANAMPINY</div>
|
||||||
<li>Tsy azo atao ny manakalo ny entana efa nofandrahana.</li>
|
<ul>
|
||||||
</ul>
|
<li>Tsy misafidy raha toa ka mamafa no ifanarahana.</li>
|
||||||
</div>
|
<li>Tsy azo atao ny mamerina vola efa naloha.</li>
|
||||||
</div>
|
<li>Tsy azo atao ny manakalo ny entana efa nofandrihana.</li>
|
||||||
|
</ul>
|
||||||
<!-- Additional space for notes -->
|
</div>
|
||||||
<div style="margin-top: 20px; padding: 10px; border: 1px solid #000; flex: 1;">
|
|
||||||
<strong>OBSERVATIONS / NOTES:</strong>
|
<!-- Signatures -->
|
||||||
<div style="height: 100px; margin-top: 10px;"></div>
|
<div class="signature-section">
|
||||||
</div>
|
<div class="signature-box">
|
||||||
|
<div class="sig-title">NY MPAMANDRIKA</div>
|
||||||
<!-- Signatures for verso -->
|
</div>
|
||||||
<div class="signature-section">
|
<div class="signature-box" style="text-align: right;">
|
||||||
<div class="signature-box">
|
<div class="sig-title">NY MPIVAROTRA</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>
|
</div>
|
||||||
</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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
HTML;
|
HTML;
|
||||||
|
|||||||
@ -100,7 +100,7 @@ class AvanceController extends AdminController
|
|||||||
$Products = new Products();
|
$Products = new Products();
|
||||||
$Notification = New NotificationController();
|
$Notification = New NotificationController();
|
||||||
|
|
||||||
if ($this->request->getMethod() === 'post' && $validation->run($validationData)) {
|
if (strtolower($this->request->getMethod()) === 'post' && $validation->run($validationData)) {
|
||||||
$session = session();
|
$session = session();
|
||||||
$users = $session->get('user');
|
$users = $session->get('user');
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ class AvanceController extends AdminController
|
|||||||
$posts = $products;
|
$posts = $products;
|
||||||
|
|
||||||
if($avance_id = $Avance->createAvance($data)){
|
if($avance_id = $Avance->createAvance($data)){
|
||||||
$Notification->createNotification('Une avance a été créé', "Conseil",$users['store_id'], 'avance');
|
$Notification->notifyGroupsByPermission('notifAvance', 'Une avance a été créé', $users['store_id'], 'avance');
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'messages' => 'Avance créé avec succès !'
|
'messages' => 'Avance créé avec succès !'
|
||||||
@ -143,7 +143,7 @@ class AvanceController extends AdminController
|
|||||||
$Products = new Products();
|
$Products = new Products();
|
||||||
$Avance = new Avance();
|
$Avance = new Avance();
|
||||||
|
|
||||||
if ($this->request->getMethod() === 'post') {
|
if (strtolower($this->request->getMethod()) === 'post') {
|
||||||
$data = [
|
$data = [
|
||||||
'customer_name' => $this->request->getPost('customer_name_avance'),
|
'customer_name' => $this->request->getPost('customer_name_avance'),
|
||||||
'customer_address'=> $this->request->getPost('customer_address_avance'),
|
'customer_address'=> $this->request->getPost('customer_address_avance'),
|
||||||
|
|||||||
@ -29,7 +29,7 @@ class CompanyController extends AdminController
|
|||||||
|
|
||||||
$Company = new Company();
|
$Company = new Company();
|
||||||
// die(var_dump($validation->getErrors()));
|
// die(var_dump($validation->getErrors()));
|
||||||
if ($this->request->getMethod() == 'post' && $validation->withRequest($this->request)->run()) {
|
if (strtolower($this->request->getMethod()) === 'post' && $validation->withRequest($this->request)->run()) {
|
||||||
// If the form is valid
|
// If the form is valid
|
||||||
$data = [
|
$data = [
|
||||||
'company_name' => $this->request->getPost('company_name'),
|
'company_name' => $this->request->getPost('company_name'),
|
||||||
@ -44,7 +44,15 @@ class CompanyController extends AdminController
|
|||||||
'message' => $this->request->getPost('message'),
|
'message' => $this->request->getPost('message'),
|
||||||
'currency' => $this->request->getPost('currency'),
|
'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)) {
|
if ($Company->updateCompany($data, 1)) {
|
||||||
session()->setFlashdata('success', 'Successfully updated');
|
session()->setFlashdata('success', 'Successfully updated');
|
||||||
return redirect()->to('/company');
|
return redirect()->to('/company');
|
||||||
|
|||||||
@ -284,4 +284,89 @@ class Dashboard extends AdminController
|
|||||||
return $this->render_template('dashboard', $data);
|
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
|
// Check if form validation is successful
|
||||||
if ($this->request->getMethod() == 'post') {
|
if (strtolower($this->request->getMethod()) === 'post') {
|
||||||
|
|
||||||
if ($validation->withRequest($this->request)->run()) {
|
if ($validation->withRequest($this->request)->run()) {
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ class GroupController extends AdminController
|
|||||||
'group_name' => 'required',
|
'group_name' => 'required',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($this->request->getMethod() === 'post') {
|
if (strtolower($this->request->getMethod()) === 'post') {
|
||||||
|
|
||||||
if ($validation->withRequest($this->request)->run()) {
|
if ($validation->withRequest($this->request)->run()) {
|
||||||
// Validation passed
|
// Validation passed
|
||||||
@ -149,7 +149,7 @@ class GroupController extends AdminController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Vérifier si c'est une requête POST avec confirmation
|
// Vérifier si c'est une requête POST avec confirmation
|
||||||
if ($this->request->getMethod() === 'post' && $this->request->getPost('confirm')) {
|
if (strtolower($this->request->getMethod()) === 'post' && $this->request->getPost('confirm')) {
|
||||||
|
|
||||||
// Supprimer d'abord toutes les associations dans user_group
|
// Supprimer d'abord toutes les associations dans user_group
|
||||||
$groupsModel->removeUsersFromGroup($id);
|
$groupsModel->removeUsersFromGroup($id);
|
||||||
|
|||||||
@ -71,6 +71,7 @@ class HistoriqueController extends AdminController
|
|||||||
$row['product_name'] ?? 'N/A',
|
$row['product_name'] ?? 'N/A',
|
||||||
$row['sku'] ?? 'N/A',
|
$row['sku'] ?? 'N/A',
|
||||||
$row['store_name'] ?? 'N/A',
|
$row['store_name'] ?? 'N/A',
|
||||||
|
$row['user_name'] ?? 'N/A',
|
||||||
$this->getActionBadge($row['action']),
|
$this->getActionBadge($row['action']),
|
||||||
$row['description'] ?? ''
|
$row['description'] ?? ''
|
||||||
];
|
];
|
||||||
|
|||||||
@ -298,7 +298,7 @@ class MecanicienController extends AdminController
|
|||||||
$date_debut = date("d/m/Y", strtotime($repa['reparation_debut']));
|
$date_debut = date("d/m/Y", strtotime($repa['reparation_debut']));
|
||||||
$date_fin = date("d/m/Y", strtotime($repa['reparation_fin']));
|
$date_fin = date("d/m/Y", strtotime($repa['reparation_fin']));
|
||||||
$storeName = $repa['store_name'] ?? 'N/A';
|
$storeName = $repa['store_name'] ?? 'N/A';
|
||||||
|
|
||||||
$result['data'][$key] = [
|
$result['data'][$key] = [
|
||||||
$user_name,
|
$user_name,
|
||||||
$image,
|
$image,
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
namespace App\Controllers;
|
namespace App\Controllers;
|
||||||
|
|
||||||
use App\Models\Notification;
|
use App\Models\Notification;
|
||||||
|
use App\Models\Groups;
|
||||||
|
use App\Models\Stores;
|
||||||
|
|
||||||
class NotificationController extends AdminController
|
class NotificationController extends AdminController
|
||||||
{
|
{
|
||||||
@ -44,6 +46,27 @@ class NotificationController extends AdminController
|
|||||||
$Notification->insertNotification($data);
|
$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é
|
// Marquer toutes les notifications comme lues pour l'utilisateur connecté
|
||||||
public function markAllAsRead()
|
public function markAllAsRead()
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -101,15 +101,20 @@ class ProductCOntroller extends AdminController
|
|||||||
$store_name = $store_info && isset($store_info['name']) ? $store_info['name'] : "Inconnu";
|
$store_name = $store_info && isset($store_info['name']) ? $store_info['name'] : "Inconnu";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disponibilité basée sur qty ET availability
|
// Disponibilité basée sur qty, availability et product_sold
|
||||||
|
$productSold = (int)($value['product_sold'] ?? 0);
|
||||||
$isInStock = ((int)$value['qty'] > 0);
|
$isInStock = ((int)$value['qty'] > 0);
|
||||||
$isAvailable = ((int)$value['availability'] === 1);
|
$isAvailable = ((int)$value['availability'] === 1);
|
||||||
|
|
||||||
$isProductAvailable = $isInStock && $isAvailable;
|
if ($productSold === 2) {
|
||||||
|
$availability = '<span class="label label-warning">En attente de livraison</span>';
|
||||||
$availability = $isProductAvailable ?
|
} elseif ($productSold === 1) {
|
||||||
'<span class="label label-success">En stock</span>' :
|
$availability = '<span class="label label-default">Livré</span>';
|
||||||
'<span class="label label-danger">Rupture</span>';
|
} elseif ($isInStock && $isAvailable) {
|
||||||
|
$availability = '<span class="label label-success">En stock</span>';
|
||||||
|
} else {
|
||||||
|
$availability = '<span class="label label-danger">Rupture</span>';
|
||||||
|
}
|
||||||
|
|
||||||
// Construction des boutons
|
// Construction des boutons
|
||||||
$buttons = '';
|
$buttons = '';
|
||||||
@ -185,7 +190,7 @@ class ProductCOntroller extends AdminController
|
|||||||
'price_min' => 'required|numeric',
|
'price_min' => 'required|numeric',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($this->request->getMethod() === 'post' && $validation->withRequest($this->request)->run()) {
|
if (strtolower($this->request->getMethod()) === 'post' && $validation->withRequest($this->request)->run()) {
|
||||||
|
|
||||||
$prix_min = (float)$this->request->getPost('price_min');
|
$prix_min = (float)$this->request->getPost('price_min');
|
||||||
$prix_vente = (float)$this->request->getPost('price_vente');
|
$prix_vente = (float)$this->request->getPost('price_vente');
|
||||||
@ -224,7 +229,7 @@ class ProductCOntroller extends AdminController
|
|||||||
'date_arivage' => $this->request->getPost('datea'),
|
'date_arivage' => $this->request->getPost('datea'),
|
||||||
'puissance' => $this->request->getPost('puissance'),
|
'puissance' => $this->request->getPost('puissance'),
|
||||||
'cler' => $this->request->getPost('cler'),
|
'cler' => $this->request->getPost('cler'),
|
||||||
'categorie_id' => json_encode($this->request->getPost('categorie[]')),
|
'categorie_id' => $this->request->getPost('categorie') ? implode(',', $this->request->getPost('categorie')) : '',
|
||||||
'etats' => $this->request->getPost('etats'),
|
'etats' => $this->request->getPost('etats'),
|
||||||
'infoManquekit' => $this->request->getPost('infoManquekit'),
|
'infoManquekit' => $this->request->getPost('infoManquekit'),
|
||||||
'info' => $this->request->getPost('info'),
|
'info' => $this->request->getPost('info'),
|
||||||
@ -243,12 +248,7 @@ class ProductCOntroller extends AdminController
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
session()->setFlashdata('success', 'Créé avec succès');
|
session()->setFlashdata('success', 'Créé avec succès');
|
||||||
$Notification->createNotification(
|
$Notification->notifyGroupsByPermission('notifProduit', "Un nouveau Produit a été créé", $store_id1, 'products/');
|
||||||
"Un nouveau Produit a été créé",
|
|
||||||
"COMMERCIALE",
|
|
||||||
$store_id1,
|
|
||||||
'products/'
|
|
||||||
);
|
|
||||||
|
|
||||||
return redirect()->to('/products');
|
return redirect()->to('/products');
|
||||||
} else {
|
} else {
|
||||||
@ -302,6 +302,11 @@ class ProductCOntroller extends AdminController
|
|||||||
|
|
||||||
public function update(int $id)
|
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();
|
$Products = new Products();
|
||||||
$Stores = new Stores();
|
$Stores = new Stores();
|
||||||
$Category = new Category();
|
$Category = new Category();
|
||||||
@ -320,33 +325,33 @@ class ProductCOntroller extends AdminController
|
|||||||
$product_data = $Products->getProductData($id);
|
$product_data = $Products->getProductData($id);
|
||||||
$prix_minimal_data = $FourchettePrix->where('product_id', $id)->first();
|
$prix_minimal_data = $FourchettePrix->where('product_id', $id)->first();
|
||||||
$prix_minimal = $prix_minimal_data['prix_minimal'] ?? '';
|
$prix_minimal = $prix_minimal_data['prix_minimal'] ?? '';
|
||||||
|
|
||||||
if ($this->request->getMethod() === 'post' && $validation->withRequest($this->request)->run()) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $validation->withRequest($this->request)->run()) {
|
||||||
|
|
||||||
$availabilityValue = (int)$this->request->getPost('availability');
|
$availabilityValue = (int)$this->request->getPost('availability');
|
||||||
$availability = ($availabilityValue === 1) ? 1 : 0;
|
$availability = ($availabilityValue === 1) ? 1 : 0;
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'name' => $this->request->getPost('nom_de_produit'),
|
'name' => $this->request->getPost('nom_de_produit') ?? '',
|
||||||
'sku' => $this->request->getPost('numero_de_serie'),
|
'sku' => $this->request->getPost('numero_de_serie') ?? '',
|
||||||
'price' => $this->request->getPost('price'),
|
'price' => $this->request->getPost('price') ?? '0',
|
||||||
'qty' => 1,
|
'qty' => 1,
|
||||||
'description' => $this->request->getPost('description'),
|
'description' => $this->request->getPost('description') ?? '',
|
||||||
'numero_de_moteur' => $this->request->getPost('numero_de_moteur'),
|
'numero_de_moteur' => $this->request->getPost('numero_de_moteur') ?? '',
|
||||||
'marque' => $this->request->getPost('marque'),
|
'marque' => $this->request->getPost('marque') ?? '0',
|
||||||
'chasis' => $this->request->getPost('chasis'),
|
'chasis' => $this->request->getPost('chasis') ?? '',
|
||||||
'store_id' => (int)$this->request->getPost('store'),
|
'store_id' => (int)$this->request->getPost('store'),
|
||||||
'availability'=> $availability,
|
'availability'=> $availability,
|
||||||
'prix_vente' => $this->request->getPost('price_vente'),
|
'prix_vente' => $this->request->getPost('price_vente') ?? '0',
|
||||||
'date_arivage'=> $this->request->getPost('datea'),
|
'date_arivage'=> $this->request->getPost('datea') ?: date('Y-m-d'),
|
||||||
'puissance' => $this->request->getPost('puissance'),
|
'puissance' => $this->request->getPost('puissance') ?? '',
|
||||||
'cler' => $this->request->getPost('cler'),
|
'cler' => $this->request->getPost('cler') ?? '',
|
||||||
'categorie_id'=> json_encode($this->request->getPost('categorie[]')),
|
'categorie_id'=> $this->request->getPost('categorie') ? implode(',', $this->request->getPost('categorie')) : '',
|
||||||
'etats' => $this->request->getPost('etats'),
|
'etats' => $this->request->getPost('etats') ?? '',
|
||||||
'infoManquekit'=> $this->request->getPost('infoManquekit'),
|
'infoManquekit'=> $this->request->getPost('infoManquekit') ?? '',
|
||||||
'info' => $this->request->getPost('info'),
|
'info' => $this->request->getPost('info') ?? '',
|
||||||
'infoManque' => $this->request->getPost('infoManque'),
|
'infoManque' => $this->request->getPost('infoManque') ?? '',
|
||||||
'type' => $this->request->getPost('type'),
|
'type' => $this->request->getPost('type') ?? '',
|
||||||
];
|
];
|
||||||
|
|
||||||
// ---- GESTION PRIX MINIMAL ----
|
// ---- GESTION PRIX MINIMAL ----
|
||||||
@ -372,17 +377,39 @@ class ProductCOntroller extends AdminController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upload image si fournie
|
// Upload image si fournie
|
||||||
if ($this->request->getFile('product_image')->isValid()) {
|
$productImage = $this->request->getFile('product_image');
|
||||||
|
if ($productImage && $productImage->isValid() && !$productImage->hasMoved()) {
|
||||||
$uploadImage = $this->uploadImage();
|
$uploadImage = $this->uploadImage();
|
||||||
$Products->update($id, ['image' => $uploadImage]);
|
$Products->update($id, ['image' => $uploadImage]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mise à jour du produit
|
// Mise à jour du produit
|
||||||
if ($Products->updateProduct($data, $id)) {
|
try {
|
||||||
session()->setFlashdata('success', 'Produit mis à jour avec succès.');
|
$db = \Config\Database::connect();
|
||||||
return redirect()->to('/products');
|
$session = session();
|
||||||
} else {
|
$currentUser = $session->get('user');
|
||||||
session()->setFlashdata('errors', 'Une erreur est survenue lors de la mise à jour.');
|
$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) {
|
||||||
|
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);
|
return redirect()->to('/products/update/' . $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -138,24 +138,30 @@ class RecouvrementController extends AdminController
|
|||||||
"data" => []
|
"data" => []
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($data as $key => $value) {
|
$hasActions = in_array('updateRecouvrement', $this->permission) || in_array('deleteRecouvrement', $this->permission);
|
||||||
$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)) {
|
foreach ($data as $key => $value) {
|
||||||
$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 = [
|
||||||
}
|
|
||||||
$result['data'][$key] = [
|
|
||||||
$value['recouvrement_id'],
|
$value['recouvrement_id'],
|
||||||
number_format($value['recouvrement_montant'], 0, '.', ' '),
|
number_format($value['recouvrement_montant'], 0, '.', ' '),
|
||||||
$value['recouvrement_date'],
|
$value['recouvrement_date'],
|
||||||
$value['recouvrement_personnel'],
|
$value['recouvrement_personnel'],
|
||||||
$value['send_money'],
|
$value['send_money'],
|
||||||
$value['get_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);
|
return $this->response->setJSON($result);
|
||||||
}
|
}
|
||||||
@ -170,24 +176,30 @@ class RecouvrementController extends AdminController
|
|||||||
"data" => []
|
"data" => []
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($data as $key => $value) {
|
$hasActions = in_array('updateRecouvrement', $this->permission) || in_array('deleteRecouvrement', $this->permission);
|
||||||
$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)) {
|
foreach ($data as $key => $value) {
|
||||||
$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 = [
|
||||||
}
|
|
||||||
$result['data'][$key] = [
|
|
||||||
$value['recouvrement_id'],
|
$value['recouvrement_id'],
|
||||||
number_format($value['recouvrement_montant'], 0, '.', ' '),
|
number_format($value['recouvrement_montant'], 0, '.', ' '),
|
||||||
$value['recouvrement_date'],
|
$value['recouvrement_date'],
|
||||||
$value['recouvrement_personnel'],
|
$value['recouvrement_personnel'],
|
||||||
$value['send_money'],
|
$value['send_money'],
|
||||||
$value['get_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);
|
return $this->response->setJSON($result);
|
||||||
}
|
}
|
||||||
@ -221,31 +233,8 @@ class RecouvrementController extends AdminController
|
|||||||
"Montant: " . number_format($recouvrementData['recouvrement_montant'], 0, ',', ' ') . " Ar<br>" .
|
"Montant: " . number_format($recouvrementData['recouvrement_montant'], 0, ',', ' ') . " Ar<br>" .
|
||||||
"Par: " . $users['firstname'] . ' ' . $users['lastname'];
|
"Par: " . $users['firstname'] . ' ' . $users['lastname'];
|
||||||
|
|
||||||
// ✅ Notifier Direction, DAF et SuperAdmin de TOUS les stores
|
// ✅ Notifier tous les groupes ayant updateRecouvrement de TOUS les stores
|
||||||
if (is_array($allStores) && count($allStores) > 0) {
|
$Notification->notifyGroupsByPermissionAllStores('notifRecouvrement', $message, 'recouvrement');
|
||||||
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) {
|
} catch (\Exception $e) {
|
||||||
log_message('error', 'Erreur notification removeRecouvrement: ' . $e->getMessage());
|
log_message('error', 'Erreur notification removeRecouvrement: ' . $e->getMessage());
|
||||||
@ -333,34 +322,8 @@ class RecouvrementController extends AdminController
|
|||||||
"Store: " . $this->returnStoreName($users['store_id']) . "<br>" .
|
"Store: " . $this->returnStoreName($users['store_id']) . "<br>" .
|
||||||
"Par: " . $fullname;
|
"Par: " . $fullname;
|
||||||
|
|
||||||
// ✅ Notifier Direction, DAF et SuperAdmin de TOUS les stores
|
// ✅ Notifier tous les groupes ayant updateRecouvrement de TOUS les stores
|
||||||
if (is_array($allStores) && count($allStores) > 0) {
|
$Notification->notifyGroupsByPermissionAllStores('notifRecouvrement', $message, 'recouvrement');
|
||||||
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) {
|
} catch (\Exception $e) {
|
||||||
log_message('error', 'Erreur notification createRecouvrement: ' . $e->getMessage());
|
log_message('error', 'Erreur notification createRecouvrement: ' . $e->getMessage());
|
||||||
@ -405,7 +368,7 @@ class RecouvrementController extends AdminController
|
|||||||
|
|
||||||
$Recouvrement = new Recouvrement();
|
$Recouvrement = new Recouvrement();
|
||||||
|
|
||||||
if ($this->request->getMethod() === 'post') {
|
if (strtolower($this->request->getMethod()) === 'post') {
|
||||||
$data = [
|
$data = [
|
||||||
'recouvrement_montant' => (int) $this->request->getPost('recouvrement_montant_edit'),
|
'recouvrement_montant' => (int) $this->request->getPost('recouvrement_montant_edit'),
|
||||||
'recouvrement_date' => $this->request->getPost('recouvrement_date_edit')
|
'recouvrement_date' => $this->request->getPost('recouvrement_date_edit')
|
||||||
@ -426,31 +389,8 @@ class RecouvrementController extends AdminController
|
|||||||
"Nouveau montant: " . number_format($data['recouvrement_montant'], 0, ',', ' ') . " Ar<br>" .
|
"Nouveau montant: " . number_format($data['recouvrement_montant'], 0, ',', ' ') . " Ar<br>" .
|
||||||
"Par: " . $users['firstname'] . ' ' . $users['lastname'];
|
"Par: " . $users['firstname'] . ' ' . $users['lastname'];
|
||||||
|
|
||||||
// ✅ Notifier Direction, DAF et SuperAdmin de TOUS les stores
|
// ✅ Notifier tous les groupes ayant updateRecouvrement de TOUS les stores
|
||||||
if (is_array($allStores) && count($allStores) > 0) {
|
$Notification->notifyGroupsByPermissionAllStores('notifRecouvrement', $message, 'recouvrement');
|
||||||
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) {
|
} catch (\Exception $e) {
|
||||||
log_message('error', 'Erreur notification updateRecouvrement: ' . $e->getMessage());
|
log_message('error', 'Erreur notification updateRecouvrement: ' . $e->getMessage());
|
||||||
|
|||||||
@ -5,8 +5,11 @@ namespace App\Controllers;
|
|||||||
use App\Controllers\AdminController;
|
use App\Controllers\AdminController;
|
||||||
use App\Models\Notification;
|
use App\Models\Notification;
|
||||||
use App\Models\Orders;
|
use App\Models\Orders;
|
||||||
|
use App\Models\OrderItems;
|
||||||
|
use App\Models\Products;
|
||||||
use App\Models\Remise;
|
use App\Models\Remise;
|
||||||
use App\Models\Stores;
|
use App\Models\Stores;
|
||||||
|
use App\Models\Historique;
|
||||||
|
|
||||||
class RemiseController extends AdminController
|
class RemiseController extends AdminController
|
||||||
{
|
{
|
||||||
@ -19,7 +22,10 @@ class RemiseController extends AdminController
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$this->verifyRole('viewRemise');
|
if (!in_array('viewRemise', $this->permission) && !in_array('validateRemise', $this->permission)) {
|
||||||
|
redirect()->to('/')->send();
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
$data = json_decode($this->fetchTotal(),true);
|
$data = json_decode($this->fetchTotal(),true);
|
||||||
|
|
||||||
@ -58,22 +64,17 @@ class RemiseController extends AdminController
|
|||||||
foreach ($data as $key => $value) {
|
foreach ($data as $key => $value) {
|
||||||
$buttons = '';
|
$buttons = '';
|
||||||
|
|
||||||
// ✅ SEUL LE SUPERADMIN PEUT VALIDER/REFUSER
|
// ✅ TOUS LES GROUPES AYANT validateRemise PEUVENT VALIDER/REFUSER
|
||||||
if ($role === 'SuperAdmin' && $value['demande_status'] == 'En attente') {
|
if (in_array('validateRemise', $this->permission) && $value['demande_status'] == 'En attente') {
|
||||||
$buttons .= '<button type="submit" class="btn btn-success" onclick="valideFunc(' . $value['id_demande'] . ')">';
|
$buttons .= '<button type="submit" class="btn btn-success" onclick="valideFunc(' . $value['id_demande'] . ')">';
|
||||||
$buttons .= '<i class="fa fa-check-circle"></i>';
|
$buttons .= '<i class="fa fa-check-circle"></i>';
|
||||||
$buttons .= '</button>';
|
$buttons .= '</button>';
|
||||||
|
|
||||||
$buttons .= ' <button type="button" class="btn btn-danger" onclick="refuseFunc(' . $value['id_demande'] . ')">';
|
$buttons .= ' <button type="button" class="btn btn-danger" onclick="refuseFunc(' . $value['id_demande'] . ')">';
|
||||||
$buttons .= '<i class="fa fa-times-circle"></i>';
|
$buttons .= '<i class="fa fa-times-circle"></i>';
|
||||||
$buttons .= '</button>';
|
$buttons .= '</button>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ DIRECTION ET DAF VOIENT SEULEMENT (pas de boutons d'action)
|
|
||||||
if (in_array($role, ['Direction', 'DAF'])) {
|
|
||||||
$buttons = '<span class="label label-info">Consultation uniquement</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$result['data'][$key] = [
|
$result['data'][$key] = [
|
||||||
$value['id_demande'],
|
$value['id_demande'],
|
||||||
$value['product'],
|
$value['product'],
|
||||||
@ -92,19 +93,10 @@ class RemiseController extends AdminController
|
|||||||
*/
|
*/
|
||||||
public function updateRemise($id_demande)
|
public function updateRemise($id_demande)
|
||||||
{
|
{
|
||||||
// ✅ VÉRIFIER QUE SEUL LE SUPERADMIN PEUT VALIDER
|
$this->verifyRole('validateRemise');
|
||||||
|
|
||||||
$session = session();
|
$session = session();
|
||||||
$user = $session->get('user');
|
$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();
|
$validation = \Config\Services::validation();
|
||||||
$data['page_title'] = $this->pageTitle;
|
$data['page_title'] = $this->pageTitle;
|
||||||
@ -119,7 +111,7 @@ class RemiseController extends AdminController
|
|||||||
|
|
||||||
$Remise = new Remise();
|
$Remise = new Remise();
|
||||||
|
|
||||||
if ($this->request->getMethod() == 'post') {
|
if (strtolower($this->request->getMethod()) === 'post') {
|
||||||
$today = date('Y-m-d');
|
$today = date('Y-m-d');
|
||||||
$demande_status = $this->request->getPost('demande_status');
|
$demande_status = $this->request->getPost('demande_status');
|
||||||
|
|
||||||
@ -160,42 +152,35 @@ class RemiseController extends AdminController
|
|||||||
if ($demande_status == 'Refusé') {
|
if ($demande_status == 'Refusé') {
|
||||||
if ($order_id) {
|
if ($order_id) {
|
||||||
$ordersModel->update($order_id, ['paid_status' => 0]);
|
$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
|
// Message de refus
|
||||||
$messageRefus = "❌ Demande de remise refusée : {$bill_no}<br>" .
|
$messageRefus = "❌ Demande de remise refusée : {$bill_no}<br>" .
|
||||||
"Produit : {$remise_product}<br>" .
|
"Produit : {$remise_product}<br>" .
|
||||||
"Décision : SuperAdmin";
|
"Décision : {$user['firstname']} {$user['lastname']} ({$user['group_name']})";
|
||||||
|
|
||||||
// Notifier le commercial du store concerné
|
// Notifier les commerciaux du store concerné
|
||||||
$Notification->createNotification(
|
$Notification->notifyGroupsByPermission('notifRemise', $messageRefus . "<br><em>Veuillez modifier la commande.</em>", (int)$store_id, "orders");
|
||||||
$messageRefus . "<br><em>Veuillez modifier la commande.</em>",
|
|
||||||
"COMMERCIALE",
|
// ✅ NOTIFIER TOUS LES GROUPES AYANT validateRemise (POUR INFORMATION)
|
||||||
(int)$store_id,
|
$Notification->notifyGroupsByPermissionAllStores('notifRemise', $messageRefus . "<br><em>Pour information</em>", 'remise/');
|
||||||
"orders"
|
|
||||||
);
|
|
||||||
|
|
||||||
// ✅ 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.';
|
$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é') {
|
} elseif ($demande_status == 'Accepté' || $demande_status == 'Validé') {
|
||||||
// ✅ SI ACCEPTÉ PAR LE SUPERADMIN
|
// ✅ SI ACCEPTÉ PAR LE SUPERADMIN
|
||||||
if ($order_id) {
|
if ($order_id) {
|
||||||
@ -204,44 +189,22 @@ class RemiseController extends AdminController
|
|||||||
|
|
||||||
$messageAcceptation = "✅ Demande de remise acceptée : {$bill_no}<br>" .
|
$messageAcceptation = "✅ Demande de remise acceptée : {$bill_no}<br>" .
|
||||||
"Produit : {$remise_product}<br>" .
|
"Produit : {$remise_product}<br>" .
|
||||||
"Décision : SuperAdmin";
|
"Décision : {$user['firstname']} {$user['lastname']} ({$user['group_name']})";
|
||||||
|
|
||||||
// Notifier la Caissière du store concerné
|
// Notifier les caissières du store concerné
|
||||||
$Notification->createNotification(
|
$Notification->notifyGroupsByPermission('notifSortieCaisse', $messageAcceptation . "<br><em>Commande prête à être traitée</em>", (int)$store_id, "orders");
|
||||||
$messageAcceptation . "<br><em>Commande prête à être traitée</em>",
|
|
||||||
"Caissière",
|
// Notifier les commerciaux du store concerné
|
||||||
(int)$store_id,
|
$Notification->notifyGroupsByPermission('notifRemise', $messageAcceptation, (int)$store_id, "orders");
|
||||||
"orders"
|
|
||||||
);
|
// ✅ NOTIFIER TOUS LES GROUPES AYANT validateRemise (POUR INFORMATION)
|
||||||
|
$Notification->notifyGroupsByPermissionAllStores('notifRemise', $messageAcceptation . "<br><em>Pour information</em>", 'remise/');
|
||||||
// Notifier le commercial du store concerné
|
|
||||||
$Notification->createNotification(
|
|
||||||
$messageAcceptation,
|
|
||||||
"COMMERCIALE",
|
|
||||||
(int)$store_id,
|
|
||||||
"orders"
|
|
||||||
);
|
|
||||||
|
|
||||||
// ✅ NOTIFIER DIRECTION ET DAF DE TOUS LES STORES (POUR INFORMATION)
|
|
||||||
if (is_array($allStores) && count($allStores) > 0) {
|
|
||||||
foreach ($allStores as $store) {
|
|
||||||
$Notification->createNotification(
|
|
||||||
$messageAcceptation . "<br><em>Pour information</em>",
|
|
||||||
"Direction",
|
|
||||||
(int)$store['id'],
|
|
||||||
'remise/'
|
|
||||||
);
|
|
||||||
|
|
||||||
$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.';
|
$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([
|
return $this->response->setJSON([
|
||||||
|
|||||||
@ -25,102 +25,125 @@ class ReportController extends AdminController
|
|||||||
{
|
{
|
||||||
$this->verifyRole('viewReports');
|
$this->verifyRole('viewReports');
|
||||||
$data['page_title'] = $this->pageTitle;
|
$data['page_title'] = $this->pageTitle;
|
||||||
|
|
||||||
// Get the current year or the selected year from the form
|
// Get the current year or the selected year from the form
|
||||||
$today_year = date('Y');
|
$today_year = date('Y');
|
||||||
if ($this->request->getPost('select_year')) {
|
if ($this->request->getPost('select_year')) {
|
||||||
$today_year = $this->request->getPost('select_year');
|
$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
|
// Fetch order data and years
|
||||||
$Reports = new Reports();
|
$Reports = new Reports();
|
||||||
$Orders = new Orders();
|
$Orders = new Orders();
|
||||||
$Store = new Stores();
|
$Store = new Stores();
|
||||||
$parking_data = $Reports->getOrderData($today_year);
|
$parking_data = $Reports->getOrderData($today_year, $startDate, $endDate, $storeId, $userId);
|
||||||
$data['report_years'] = $Reports->getOrderYear();
|
$data['report_years'] = $Reports->getOrderYear();
|
||||||
|
|
||||||
|
|
||||||
// Process the parking data and calculate total amounts
|
|
||||||
$final_parking_data = [];
|
|
||||||
foreach ($parking_data as $month => $orders) {
|
|
||||||
$total_amount_earned = 0;
|
|
||||||
|
|
||||||
if (!empty($orders)) {
|
// Charger les stores et users pour les filtres
|
||||||
foreach ($orders as $order) {
|
$data['stores'] = $Store->getActiveStore();
|
||||||
// Utiliser le montant selon la logique : discount si existe, sinon gross_amount
|
|
||||||
if (!empty($order['discount']) && $order['discount'] > 0) {
|
$db = \Config\Database::connect();
|
||||||
$total_amount_earned += (float) $order['discount'];
|
$data['users_list'] = $db->table('users u')
|
||||||
} else {
|
->select('u.id, u.firstname, u.lastname, g.group_name')
|
||||||
$total_amount_earned += (float) $order['gross_amount'];
|
->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 = [];
|
||||||
|
foreach ($parking_data as $month => $orders) {
|
||||||
|
$total_amount_earned = 0;
|
||||||
|
|
||||||
|
if (!empty($orders)) {
|
||||||
|
foreach ($orders as $order) {
|
||||||
|
if (!empty($order['discount']) && $order['discount'] > 0) {
|
||||||
|
$total_amount_earned += (float) $order['discount'];
|
||||||
|
} else {
|
||||||
|
$total_amount_earned += (float) $order['gross_amount'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$final_parking_data[$month] = $total_amount_earned;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$final_parking_data[$month] = $total_amount_earned;
|
||||||
|
}
|
||||||
|
|
||||||
// Data for the camembert (pie chart)
|
// Data for the camembert (pie chart)
|
||||||
$paymentModes = $Orders->getPaymentModes();
|
$paymentModes = $Orders->getPaymentModes($startDate, $endDate, $storeId, $userId);
|
||||||
$total_mvola1 = $paymentModes->total_mvola1;
|
$total_mvola1 = $paymentModes->total_mvola1 ?? 0;
|
||||||
$total_mvola2 = $paymentModes->total_mvola2;
|
$total_mvola2 = $paymentModes->total_mvola2 ?? 0;
|
||||||
$total_espece1 = $paymentModes->total_espece1;
|
$total_espece1 = $paymentModes->total_espece1 ?? 0;
|
||||||
$total_espece2 = $paymentModes->total_espece2;
|
$total_espece2 = $paymentModes->total_espece2 ?? 0;
|
||||||
$total_banque1 = $paymentModes->total_virement_bancaire1;
|
$total_banque1 = $paymentModes->total_virement_bancaire1 ?? 0;
|
||||||
$total_banque2 = $paymentModes->total_virement_bancaire2;
|
$total_banque2 = $paymentModes->total_virement_bancaire2 ?? 0;
|
||||||
$total_mvola = $total_mvola1 + $total_mvola2;
|
$total_mvola = $total_mvola1 + $total_mvola2;
|
||||||
$total_banque = $total_banque1 + $total_banque2;
|
$total_banque = $total_banque1 + $total_banque2;
|
||||||
$total_espece = $total_espece1 + $total_espece2;
|
$total_espece = $total_espece1 + $total_espece2;
|
||||||
$totalOrders = $Orders->getTotalOrders();
|
$totalOrders = $Orders->getTotalOrders($startDate, $endDate, $storeId, $userId);
|
||||||
$totalAmountPerPaymentModes = ["MVOLA" => $total_mvola, "Espece" => $total_espece, "Virement Bancaire" => $total_banque];
|
$totalAmountPerPaymentModes = ["MVOLA" => $total_mvola, "Espece" => $total_espece, "Virement Bancaire" => $total_banque];
|
||||||
$totalOrdersCount = (int) $totalOrders->total_orders;
|
$totalOrdersCount = (int) $totalOrders->total_orders;
|
||||||
$labels = [];
|
$labels = [];
|
||||||
$totals = [];
|
$totals = [];
|
||||||
|
|
||||||
if ($totalOrdersCount > 0) {
|
if ($totalOrdersCount > 0) {
|
||||||
foreach ($totalAmountPerPaymentModes as $mode => $total) {
|
foreach ($totalAmountPerPaymentModes as $mode => $total) {
|
||||||
$labels[] = $mode;
|
$labels[] = $mode;
|
||||||
$totals[] = $total;
|
$totals[] = $total;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$data['labels'] = json_encode($labels);
|
$data['labels'] = json_encode($labels);
|
||||||
$data['totals'] = json_encode($totals);
|
$data['totals'] = json_encode($totals);
|
||||||
|
|
||||||
// Prepare data for product chart
|
// Prepare data for product chart
|
||||||
$OrderItem = new OrderItems();
|
$OrderItem = new OrderItems();
|
||||||
$productTable = $OrderItem->getAllSoldProductToday();
|
$productTable = $OrderItem->getAllSoldProductToday($startDate, $endDate, $storeId, $userId);
|
||||||
|
|
||||||
$product_sold = (int) $productTable->total_product_sold;
|
$product_sold = (int) ($productTable->total_product_sold ?? 0);
|
||||||
$unsold_product = (int) $productTable->total_unsold_product;
|
$unsold_product = (int) ($productTable->total_unsold_product ?? 0);
|
||||||
|
|
||||||
$labels1 = ["Produits vendus", "Produits non vendus"];
|
$labels1 = ["Produits vendus", "Produits non vendus"];
|
||||||
$totals2 = [$product_sold, $unsold_product];
|
$totals2 = [$product_sold, $unsold_product];
|
||||||
|
|
||||||
$data['labels_product'] = json_encode($labels1);
|
$data['labels_product'] = json_encode($labels1);
|
||||||
$data['totals_product'] = json_encode($totals2);
|
$data['totals_product'] = json_encode($totals2);
|
||||||
|
|
||||||
// Prepare data for the view
|
// Prepare data for the view
|
||||||
$data['selected_year'] = $today_year;
|
$data['selected_year'] = $today_year;
|
||||||
$data['company_currency'] = $this->companycurrency();
|
$data['company_currency'] = $this->companycurrency();
|
||||||
$data['results'] = $final_parking_data;
|
$data['results'] = $final_parking_data;
|
||||||
|
|
||||||
// Data for the camembert in dashboard
|
// Data for the camembert in dashboard
|
||||||
$totalStoreOrder = $Orders->getTotalOrderPerStore();
|
$totalStoreOrder = $Orders->getTotalOrderPerStore($startDate, $endDate, $storeId, $userId);
|
||||||
$totalOrders = $Orders->getTotalOrders();
|
$totalOrders = $Orders->getTotalOrders($startDate, $endDate, $storeId, $userId);
|
||||||
$totalOrdersCount = (int) $totalOrders->total_orders;
|
$totalOrdersCount = (int) $totalOrders->total_orders;
|
||||||
|
|
||||||
// Initialisation des variables pour éviter l'erreur "Undefined variable"
|
// Initialisation des variables pour éviter l'erreur "Undefined variable"
|
||||||
$labelStore = [];
|
$labelStore = [];
|
||||||
$totalPerStore = [];
|
$totalPerStore = [];
|
||||||
|
|
||||||
foreach ($totalStoreOrder as $totalOrdersInStore) {
|
foreach ($totalStoreOrder as $totalOrdersInStore) {
|
||||||
$storeList = $Store->getStoreById($totalOrdersInStore->store_id);
|
$storeList = $Store->getStoreById($totalOrdersInStore->store_id);
|
||||||
$labelStore[] = $storeList->name ?? 'Inconnu';
|
$labelStore[] = $storeList->name ?? 'Inconnu';
|
||||||
$totalPerStore[] = ((int) $totalOrdersInStore->total / $totalOrdersCount) * 100;
|
$totalPerStore[] = ($totalOrdersCount > 0) ? ((int) $totalOrdersInStore->total / $totalOrdersCount) * 100 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data['labelStore'] = json_encode($labelStore);
|
$data['labelStore'] = json_encode($labelStore);
|
||||||
$data['totalPerStore'] = json_encode($totalPerStore);
|
$data['totalPerStore'] = json_encode($totalPerStore);
|
||||||
|
|
||||||
// Load the view
|
// Load the view
|
||||||
return $this->render_template('reports/index', $data);
|
return $this->render_template('reports/index', $data);
|
||||||
}
|
}
|
||||||
@ -169,13 +192,13 @@ class ReportController extends AdminController
|
|||||||
{
|
{
|
||||||
$Orders = new Orders();
|
$Orders = new Orders();
|
||||||
|
|
||||||
$productVente = $Orders->getTotalProductvente2($id);
|
$startDate = $this->request->getGet('startDate');
|
||||||
|
$endDate = $this->request->getGet('endDate');
|
||||||
|
|
||||||
|
$productVente = $Orders->getTotalProductvente2($id, $startDate, $endDate);
|
||||||
$result = ['data' => []];
|
$result = ['data' => []];
|
||||||
|
|
||||||
foreach ($productVente as $key => $value) {
|
foreach ($productVente as $key => $value) {
|
||||||
// die(var_dump($value)); // Debugging: Check what $value contains
|
|
||||||
|
|
||||||
// Add the row data
|
|
||||||
$result['data'][$key] = [
|
$result['data'][$key] = [
|
||||||
$value->sku,
|
$value->sku,
|
||||||
$value->date_time,
|
$value->date_time,
|
||||||
@ -183,7 +206,6 @@ class ReportController extends AdminController
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return data in JSON format
|
|
||||||
return $this->response->setJSON($result);
|
return $this->response->setJSON($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +223,7 @@ class ReportController extends AdminController
|
|||||||
{
|
{
|
||||||
$Products = new Products();
|
$Products = new Products();
|
||||||
|
|
||||||
$produitStock = $Products->getProductData2($id);
|
$produitStock = $Products->getStockByBrand($id);
|
||||||
$result = ['data' => []];
|
$result = ['data' => []];
|
||||||
|
|
||||||
foreach ($produitStock as $key => $value) {
|
foreach ($produitStock as $key => $value) {
|
||||||
@ -223,15 +245,13 @@ class ReportController extends AdminController
|
|||||||
{
|
{
|
||||||
$Products = new Orders();
|
$Products = new Orders();
|
||||||
|
|
||||||
$produitStock = $Products->getOrderVendue();
|
$startDate = $this->request->getGet('startDate');
|
||||||
|
$endDate = $this->request->getGet('endDate');
|
||||||
|
|
||||||
|
$produitStock = $Products->getOrderVendue($id, $startDate, $endDate);
|
||||||
$result = ['data' => []];
|
$result = ['data' => []];
|
||||||
// echo '<pre>';
|
|
||||||
// die(var_dump($produitStock));
|
|
||||||
|
|
||||||
foreach ($produitStock as $key => $value) {
|
foreach ($produitStock as $key => $value) {
|
||||||
// die(var_dump($value)); // Debugging: Check what $value contains
|
|
||||||
|
|
||||||
// Add the row data
|
|
||||||
$result['data'][$key] = [
|
$result['data'][$key] = [
|
||||||
$value['sku'],
|
$value['sku'],
|
||||||
$value['qty'],
|
$value['qty'],
|
||||||
@ -241,7 +261,6 @@ class ReportController extends AdminController
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return data in JSON format
|
|
||||||
return $this->response->setJSON($result);
|
return $this->response->setJSON($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,10 +270,24 @@ class ReportController extends AdminController
|
|||||||
$data['page_title'] = $this->pageTitle;
|
$data['page_title'] = $this->pageTitle;
|
||||||
$Stores = new Stores();
|
$Stores = new Stores();
|
||||||
|
|
||||||
// echo '<pre>';
|
|
||||||
// die(var_dump($orderTest));
|
|
||||||
$data['stores'] = $Stores->getActiveStore();
|
$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);
|
return $this->render_template('reports/performance', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,32 +298,27 @@ class ReportController extends AdminController
|
|||||||
$session = session();
|
$session = session();
|
||||||
$users = $session->get('user');
|
$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');
|
$startDate = $this->request->getGet('startDate');
|
||||||
$endDate = $this->request->getGet('endDate');
|
$endDate = $this->request->getGet('endDate');
|
||||||
$pvente = $this->request->getGet('pvente');
|
$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
|
// Pour Direction et Conseil : afficher TOUTES les performances AVEC FILTRES
|
||||||
if ($users['group_name'] === "DAF" || $users['group_name'] === "Direction" || $users['group_name'] === "SuperAdmin") {
|
if ($users['group_name'] === "DAF" || $users['group_name'] === "Direction" || $users['group_name'] === "SuperAdmin") {
|
||||||
// ✅ PASSER LES FILTRES AU MODÈLE - UNIQUEMENT POUR L'ADMIN
|
$orderPaid = $Orders->getPerformanceByOrders($startDate, $endDate, $pvente, $commercialId);
|
||||||
$orderPaid = $Orders->getPerformanceByOrders($startDate, $endDate, $pvente);
|
|
||||||
foreach ($orderPaid as $key => $value) {
|
foreach ($orderPaid as $key => $value) {
|
||||||
// Déterminer le prix de vente réel
|
$prix_vente_reel = (!empty($value['discount']) && $value['discount'] > 0)
|
||||||
$prix_vente_reel = (!empty($value['discount']) && $value['discount'] > 0)
|
? $value['discount']
|
||||||
? $value['discount']
|
|
||||||
: $value['prix_vente'];
|
: $value['prix_vente'];
|
||||||
|
|
||||||
// Calculer le bénéfice
|
|
||||||
$benefice = $prix_vente_reel - $value['price'];
|
$benefice = $prix_vente_reel - $value['price'];
|
||||||
|
|
||||||
$result['data'][$key] = [
|
$result['data'][$key] = [
|
||||||
$value['firstname'] . ' ' . $value['lastname'],
|
$value['firstname'] . ' ' . $value['lastname'],
|
||||||
$value['email'],
|
$value['email'],
|
||||||
($value['sku'] == "" ? $value['motoname'] : $value['sku']),
|
($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($value['price'], 0, '.', ' '),
|
||||||
number_format($prix_vente_reel, 0, '.', ' '),
|
number_format($prix_vente_reel, 0, '.', ' '),
|
||||||
$this->returnName($value['store_id']),
|
$this->returnName($value['store_id']),
|
||||||
@ -517,7 +545,7 @@ class ReportController extends AdminController
|
|||||||
$imageUrl, // 0 - Image
|
$imageUrl, // 0 - Image
|
||||||
$order['bill_no'] ?? 'N/A', // 1 - N° Facture
|
$order['bill_no'] ?? 'N/A', // 1 - N° Facture
|
||||||
$product['name'], // 2 - Désignation
|
$product['name'], // 2 - Désignation
|
||||||
$product['sku'], // 3 - UGS
|
$product['sku'], // 3 - N° SERIE
|
||||||
$brandName, // 4 - Marque
|
$brandName, // 4 - Marque
|
||||||
$order['customer_name'], // 5 - Client
|
$order['customer_name'], // 5 - Client
|
||||||
$agentName, // 6 - Agent Sécurité
|
$agentName, // 6 - Agent Sécurité
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use App\Models\Securite;
|
|||||||
use App\Models\Products;
|
use App\Models\Products;
|
||||||
use App\Models\Orders;
|
use App\Models\Orders;
|
||||||
use App\Models\Stores;
|
use App\Models\Stores;
|
||||||
|
use App\Models\Historique;
|
||||||
|
|
||||||
class SecuriteController extends AdminController
|
class SecuriteController extends AdminController
|
||||||
{
|
{
|
||||||
@ -48,7 +49,7 @@ class SecuriteController extends AdminController
|
|||||||
|
|
||||||
// Bouton d’action
|
// Bouton d’action
|
||||||
$buttons = in_array('validateCommande1', $this->permission)
|
$buttons = in_array('validateCommande1', $this->permission)
|
||||||
? '<button type="button" class="btn btn-success" onclick="editFunc(' . $securite['id'] . ')" data-toggle="modal" data-target="#editModal"><i class="fa fa-check"></i></button>'
|
? '<button type="button" class="btn btn-success" onclick="editFunc(' . $securite['id'] . ')"><i class="fa fa-check"></i></button>'
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
// Statut
|
// Statut
|
||||||
@ -60,7 +61,7 @@ class SecuriteController extends AdminController
|
|||||||
|
|
||||||
$result['data'][] = [
|
$result['data'][] = [
|
||||||
'image' => $img,
|
'image' => $img,
|
||||||
'ugs' => esc($product['sku']),
|
'num_serie' => esc($product['sku']),
|
||||||
'designation' => esc($product['name']),
|
'designation' => esc($product['name']),
|
||||||
'statut' => $statut,
|
'statut' => $statut,
|
||||||
'action' => $buttons
|
'action' => $buttons
|
||||||
@ -87,7 +88,7 @@ class SecuriteController extends AdminController
|
|||||||
$response = [
|
$response = [
|
||||||
'image' => base_url('assets/images/product_image/' . $product['image']),
|
'image' => base_url('assets/images/product_image/' . $product['image']),
|
||||||
'nom' => $product['name'],
|
'nom' => $product['name'],
|
||||||
'ugs' => $product['sku'],
|
'num_serie' => $product['sku'],
|
||||||
'bill_no' => $data['bill_no'],
|
'bill_no' => $data['bill_no'],
|
||||||
'customer_name' => $order_data['customer_name'],
|
'customer_name' => $order_data['customer_name'],
|
||||||
'customer_address' => $order_data['customer_address'],
|
'customer_address' => $order_data['customer_address'],
|
||||||
@ -102,7 +103,7 @@ class SecuriteController extends AdminController
|
|||||||
public function update(int $id)
|
public function update(int $id)
|
||||||
{
|
{
|
||||||
$this->verifyRole('updateCommande1');
|
$this->verifyRole('updateCommande1');
|
||||||
$storeModel = new Securite();
|
$securiteModel = new Securite();
|
||||||
$post = $this->request->getPost();
|
$post = $this->request->getPost();
|
||||||
$response = [];
|
$response = [];
|
||||||
|
|
||||||
@ -113,12 +114,40 @@ class SecuriteController extends AdminController
|
|||||||
];
|
];
|
||||||
$session = session();
|
$session = session();
|
||||||
$users = $session->get('user');
|
$users = $session->get('user');
|
||||||
$Notification = new NotificationController();
|
$Notification = new NotificationController();
|
||||||
if ($storeModel->updateSecurite($data, $id)) {
|
|
||||||
|
if ($securiteModel->updateSecurite($data, $id)) {
|
||||||
if ($post['status'] === "Validé") {
|
if ($post['status'] === "Validé") {
|
||||||
$Notification->createNotification('Une commande a été validé', "COMMERCIALE",(int)$users['store_id'], 'orders');
|
// ✅ 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->notifyGroupsByPermission('notifRemise', 'Une commande a été validée et livrée', (int)$users['store_id'], 'orders');
|
||||||
}
|
}
|
||||||
$response = ['success' => true, 'messages' => 'Mise à jour réussie'];
|
// 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'];
|
||||||
} else {
|
} else {
|
||||||
$response = ['success' => false, 'messages' => 'Erreur en base lors de la mise à jour'];
|
$response = ['success' => false, 'messages' => 'Erreur en base lors de la mise à jour'];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -574,16 +574,7 @@ public function markAsPaid($id_sortie)
|
|||||||
"Store: " . $this->returnStoreName($decaissement['store_id']) . "<br>" .
|
"Store: " . $this->returnStoreName($decaissement['store_id']) . "<br>" .
|
||||||
"Nouveau solde " . $mode_paiement_label . ": " . number_format($fonds_disponible - $montant_retire, 0, ',', ' ') . " Ar";
|
"Nouveau solde " . $mode_paiement_label . ": " . number_format($fonds_disponible - $montant_retire, 0, ',', ' ') . " Ar";
|
||||||
|
|
||||||
$Stores = new Stores();
|
$Notification->notifyGroupsByPermissionAllStores('notifSortieCaisse', $message, 'sortieCaisse');
|
||||||
$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) {
|
} catch (\Exception $e) {
|
||||||
log_message('error', 'Erreur notification markAsPaid: ' . $e->getMessage());
|
log_message('error', 'Erreur notification markAsPaid: ' . $e->getMessage());
|
||||||
@ -856,16 +847,7 @@ public function markAsPaid($id_sortie)
|
|||||||
"Store: " . $this->returnStoreName($user['store_id']) . "<br>" .
|
"Store: " . $this->returnStoreName($user['store_id']) . "<br>" .
|
||||||
"Demandeur: " . $user['firstname'] . ' ' . $user['lastname'];
|
"Demandeur: " . $user['firstname'] . ' ' . $user['lastname'];
|
||||||
|
|
||||||
$Stores = new Stores();
|
$Notification->notifyGroupsByPermissionAllStores('notifSortieCaisse', $message, 'sortieCaisse');
|
||||||
$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) {
|
} catch (\Exception $e) {
|
||||||
log_message('error', 'Erreur notification createSortieCaisse: ' . $e->getMessage());
|
log_message('error', 'Erreur notification createSortieCaisse: ' . $e->getMessage());
|
||||||
@ -899,7 +881,7 @@ public function markAsPaid($id_sortie)
|
|||||||
|
|
||||||
$data['page_title'] = $this->pageTitle;
|
$data['page_title'] = $this->pageTitle;
|
||||||
|
|
||||||
if ($this->request->getMethod() === 'post') {
|
if (strtolower($this->request->getMethod()) === 'post') {
|
||||||
$validation = \Config\Services::validation();
|
$validation = \Config\Services::validation();
|
||||||
|
|
||||||
$validation->setRules([
|
$validation->setRules([
|
||||||
@ -1032,7 +1014,7 @@ public function markAsPaid($id_sortie)
|
|||||||
|
|
||||||
$data['page_title'] = $this->pageTitle;
|
$data['page_title'] = $this->pageTitle;
|
||||||
|
|
||||||
if ($this->request->getMethod() === 'post') {
|
if (strtolower($this->request->getMethod()) === 'post') {
|
||||||
$data = [
|
$data = [
|
||||||
'admin_raison' => $this->request->getPost('admin_raison'),
|
'admin_raison' => $this->request->getPost('admin_raison'),
|
||||||
'statut' => $this->request->getPost('statut'),
|
'statut' => $this->request->getPost('statut'),
|
||||||
@ -1054,15 +1036,15 @@ public function markAsPaid($id_sortie)
|
|||||||
switch ($statut) {
|
switch ($statut) {
|
||||||
case "Valider":
|
case "Valider":
|
||||||
$message = "✅ Le décaissement a été validé par la Direction<br>Store: " . $this->returnStoreName($store_id);
|
$message = "✅ Le décaissement a été validé par la Direction<br>Store: " . $this->returnStoreName($store_id);
|
||||||
$Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse');
|
$Notification->notifyGroupsByPermission('notifSortieCaisse', $message, (int)$store_id, 'sortieCaisse');
|
||||||
break;
|
break;
|
||||||
case "Refuser":
|
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');
|
$message = "❌ Le décaissement a été refusé par la Direction<br>Store: " . $this->returnStoreName($store_id) . "<br>Raison: " . $this->request->getPost('admin_raison');
|
||||||
$Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse');
|
$Notification->notifyGroupsByPermission('notifSortieCaisse', $message, (int)$store_id, 'sortieCaisse');
|
||||||
break;
|
break;
|
||||||
case "En attente":
|
case "En attente":
|
||||||
$message = "⏳ Le décaissement a été mis en attente par la Direction<br>Store: " . $this->returnStoreName($store_id);
|
$message = "⏳ Le décaissement a été mis en attente par la Direction<br>Store: " . $this->returnStoreName($store_id);
|
||||||
$Notification->createNotification($message, "Caissière", (int)$store_id, 'sortieCaisse');
|
$Notification->notifyGroupsByPermission('notifSortieCaisse', $message, (int)$store_id, 'sortieCaisse');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -209,7 +209,7 @@ class UserController extends AdminController
|
|||||||
$data['page_title'] = $this->pageTitle;
|
$data['page_title'] = $this->pageTitle;
|
||||||
|
|
||||||
// Check if it's a POST request before validating
|
// Check if it's a POST request before validating
|
||||||
if ($this->request->getMethod() === 'post') {
|
if (strtolower($this->request->getMethod()) === 'post') {
|
||||||
// Load validation service and run validation
|
// Load validation service and run validation
|
||||||
if (!$this->validate($validationRules)) {
|
if (!$this->validate($validationRules)) {
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ class UserController extends AdminController
|
|||||||
// Check if the ID exists in the request
|
// Check if the ID exists in the request
|
||||||
if ($id) {
|
if ($id) {
|
||||||
// Check if it's a POST request before validating
|
// Check if it's a POST request before validating
|
||||||
if ($this->request->getMethod() === 'post') {
|
if (strtolower($this->request->getMethod()) === 'post') {
|
||||||
// Validate the form
|
// Validate the form
|
||||||
if (!$this->validate($validationRules)) {
|
if (!$this->validate($validationRules)) {
|
||||||
// Validation failed
|
// Validation failed
|
||||||
@ -405,7 +405,7 @@ class UserController extends AdminController
|
|||||||
]);
|
]);
|
||||||
$Users = new Users();
|
$Users = new Users();
|
||||||
// If validation passes for the first set of rules
|
// If validation passes for the first set of rules
|
||||||
if ($this->request->getMethod() === 'post' && $validation->withRequest($this->request)->run()) {
|
if (strtolower($this->request->getMethod()) === 'post' && $validation->withRequest($this->request)->run()) {
|
||||||
// Handle the case when password is not being updated
|
// Handle the case when password is not being updated
|
||||||
if (empty($this->request->getPost('password')) && empty($this->request->getPost('cpassword'))) {
|
if (empty($this->request->getPost('password')) && empty($this->request->getPost('cpassword'))) {
|
||||||
|
|
||||||
|
|||||||
@ -189,20 +189,26 @@ class Avance extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ✅ CORRECTION : getTotalAvance pour la caissière
|
// ✅ CORRECTION : getTotalAvance pour la caissière
|
||||||
public function getTotalAvance() {
|
public function getTotalAvance($startDate = null, $endDate = null) {
|
||||||
$session = session();
|
$session = session();
|
||||||
$users = $session->get('user');
|
$users = $session->get('user');
|
||||||
$isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction','DAF']);
|
$isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction','DAF']);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$builder = $this->select('SUM(avance_amount) AS ta')
|
$builder = $this->select('SUM(avance_amount) AS ta')
|
||||||
->where('is_order', 0)
|
->where('is_order', 0)
|
||||||
->where('active', 1); // ✅ Ajout du filtre active
|
->where('active', 1);
|
||||||
|
|
||||||
if (!$isAdmin) {
|
if (!$isAdmin) {
|
||||||
$builder->where('store_id', $users['store_id']); // ✅ Filtre par store pour caissière
|
$builder->where('store_id', $users['store_id']);
|
||||||
}
|
}
|
||||||
|
if ($startDate) {
|
||||||
|
$builder->where('DATE(avance_date) >=', $startDate);
|
||||||
|
}
|
||||||
|
if ($endDate) {
|
||||||
|
$builder->where('DATE(avance_date) <=', $endDate);
|
||||||
|
}
|
||||||
|
|
||||||
return $builder->get()->getRowObject();
|
return $builder->get()->getRowObject();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
log_message('error', 'Erreur lors du total du montant des avances : ' . $e->getMessage());
|
log_message('error', 'Erreur lors du total du montant des avances : ' . $e->getMessage());
|
||||||
@ -212,7 +218,7 @@ class Avance extends Model {
|
|||||||
|
|
||||||
// ✅ CORRECTION PRINCIPALE : getPaymentModesAvance pour la caissière
|
// ✅ CORRECTION PRINCIPALE : getPaymentModesAvance pour la caissière
|
||||||
// ✅ MODIFICATION : Ne compter QUE les avances VALIDÉES
|
// ✅ MODIFICATION : Ne compter QUE les avances VALIDÉES
|
||||||
public function getPaymentModesAvance()
|
public function getPaymentModesAvance($startDate = null, $endDate = null)
|
||||||
{
|
{
|
||||||
$session = session();
|
$session = session();
|
||||||
$users = $session->get('user');
|
$users = $session->get('user');
|
||||||
@ -226,14 +232,19 @@ public function getPaymentModesAvance()
|
|||||||
SUM(CASE WHEN LOWER(type_payment) = "en espèce" THEN avance_amount ELSE 0 END) AS total_espece,
|
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
|
SUM(CASE WHEN LOWER(type_payment) = "virement bancaire" THEN avance_amount ELSE 0 END) AS total_virement_bancaire
|
||||||
')
|
')
|
||||||
->where('validated', 1) // ✅ AJOUT : Uniquement les avances validées
|
->where('validated', 1)
|
||||||
->where('active', 1)
|
->where('active', 1)
|
||||||
->where('is_order', 0);
|
->where('is_order', 0);
|
||||||
|
|
||||||
// ✅ Filtre par store pour non-admin
|
|
||||||
if (!$isAdmin) {
|
if (!$isAdmin) {
|
||||||
$builder->where('store_id', $users['store_id']);
|
$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();
|
$result = $builder->get()->getRowObject();
|
||||||
|
|
||||||
@ -442,9 +453,11 @@ public function getPaymentModesAvance()
|
|||||||
$isCommercial = in_array($users['group_name'], ['COMMERCIALE']);
|
$isCommercial = in_array($users['group_name'], ['COMMERCIALE']);
|
||||||
$isCaissier = in_array($users['group_name'], ['Caissière']);
|
$isCaissier = in_array($users['group_name'], ['Caissière']);
|
||||||
|
|
||||||
$builder = $this->where('is_order', 0)
|
$builder = $this->where('amount_due', 0)
|
||||||
->where('active', 1)
|
->groupStart()
|
||||||
->where('amount_due', 0);
|
->where('active', 1)
|
||||||
|
->orWhere('is_order', 1)
|
||||||
|
->groupEnd();
|
||||||
|
|
||||||
if ($isCommercial) {
|
if ($isCommercial) {
|
||||||
$builder->where('user_id', $users['id']);
|
$builder->where('user_id', $users['id']);
|
||||||
|
|||||||
@ -13,7 +13,7 @@ class Company extends Model
|
|||||||
protected $table = 'company';
|
protected $table = 'company';
|
||||||
// List all the fields that are allowed to be updated or inserted
|
// List all the fields that are allowed to be updated or inserted
|
||||||
protected $allowedFields = [
|
protected $allowedFields = [
|
||||||
'company_name', 'service_charge_value', 'vat_charge_value', 'address', 'phone', 'phone2', 'NIF', 'STAT', 'country', 'message', 'currency',
|
'company_name', 'service_charge_value', 'vat_charge_value', 'address', 'phone', 'phone2', 'NIF', 'STAT', 'country', 'message', 'currency', 'logo',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -99,4 +99,22 @@ class Groups extends Model
|
|||||||
->get()
|
->get()
|
||||||
->getRowArray();
|
->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,6 +16,8 @@ class Historique extends Model
|
|||||||
'sku',
|
'sku',
|
||||||
'store_name',
|
'store_name',
|
||||||
'description',
|
'description',
|
||||||
|
'user_id',
|
||||||
|
'user_name',
|
||||||
'created_at'
|
'created_at'
|
||||||
];
|
];
|
||||||
protected $useTimestamps = false;
|
protected $useTimestamps = false;
|
||||||
@ -111,6 +113,32 @@ class Historique extends Model
|
|||||||
return $this->insert($data);
|
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)
|
* Nettoyer l'historique ancien (plus de X jours)
|
||||||
*/
|
*/
|
||||||
@ -164,7 +192,7 @@ class Historique extends Model
|
|||||||
{
|
{
|
||||||
$data = $this->getHistoriqueWithFilters($filters);
|
$data = $this->getHistoriqueWithFilters($filters);
|
||||||
|
|
||||||
$csvData = "ID,Table,Action,ID Produit,Nom Produit,SKU,Magasin,Description,Date/Heure\n";
|
$csvData = "ID,Table,Action,ID Produit,Nom Produit,N° de série,Magasin,Description,Date/Heure\n";
|
||||||
|
|
||||||
foreach ($data as $row) {
|
foreach ($data as $row) {
|
||||||
$csvData .= '"' . $row['id'] . '",';
|
$csvData .= '"' . $row['id'] . '",';
|
||||||
|
|||||||
@ -24,15 +24,32 @@ class OrderItems extends Model
|
|||||||
return $this->where('order_id', $order_id)->findAll();
|
return $this->where('order_id', $order_id)->findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAllSoldProductToday() {
|
public function getAllSoldProductToday($startDate = null, $endDate = null, $storeId = null, $userId = null) {
|
||||||
return $this->select('
|
$builder = $this->select('
|
||||||
COUNT(orders_item.id) as total_product_sold,
|
COUNT(orders_item.id) as total_product_sold,
|
||||||
(SELECT SUM(products.qty) FROM products) as total_unsold_product
|
(SELECT SUM(products.qty) FROM products) as total_unsold_product
|
||||||
')
|
')
|
||||||
->join('orders', 'orders_item.order_id = orders.id')
|
->join('orders', 'orders_item.order_id = orders.id');
|
||||||
->where('DATE(orders.date_time)', date('Y-m-d'))
|
|
||||||
->get()
|
if (!empty($startDate) || !empty($endDate) || !empty($storeId) || !empty($userId)) {
|
||||||
->getRow();
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSumOrdersItemData($order_id = null)
|
public function getSumOrdersItemData($order_id = null)
|
||||||
|
|||||||
@ -124,6 +124,7 @@ class Orders extends Model
|
|||||||
->join('orders_item', 'orders_item.order_id = orders.id', 'left')
|
->join('orders_item', 'orders_item.order_id = orders.id', 'left')
|
||||||
->join('products', 'products.id = orders_item.product_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("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');
|
->groupBy('orders.id');
|
||||||
|
|
||||||
// Récupération du groupe de l'utilisateur
|
// Récupération du groupe de l'utilisateur
|
||||||
@ -274,15 +275,15 @@ class Orders extends Model
|
|||||||
$orderItemModel->where('order_id', $id)->delete();
|
$orderItemModel->where('order_id', $id)->delete();
|
||||||
|
|
||||||
// Insert new items
|
// Insert new items
|
||||||
$count_product = count($data['product']);
|
$count_product = is_array($data['product']) ? count($data['product']) : 0;
|
||||||
for ($x = 0; $x < $count_product; $x++) {
|
for ($x = 0; $x < $count_product; $x++) {
|
||||||
$items = [
|
$items = [
|
||||||
'order_id' => $id,
|
'order_id' => $id,
|
||||||
'product_id' => $data['product'][$x],
|
'product_id' => is_array($data['product']) ? $data['product'][$x] : $data['product'],
|
||||||
'rate' => $data['rate_value'][$x],
|
'rate' => is_array($data['rate_value']) ? ($data['rate_value'][$x] ?? 0) : ($data['rate_value'] ?? 0),
|
||||||
'qty' => isset($data['qty'][$x]) ? (int)$data['qty'][$x] : 1,
|
'qty' => is_array($data['qty']) ? (int)($data['qty'][$x] ?? 1) : 1,
|
||||||
'puissance' => $data['puissance'][$x],
|
'puissance' => is_array($data['puissance']) ? ($data['puissance'][$x] ?? '') : ($data['puissance'] ?? ''),
|
||||||
'amount' => $data['amount_value'][$x],
|
'amount' => is_array($data['amount_value']) ? ($data['amount_value'][$x] ?? 0) : ($data['amount_value'] ?? 0),
|
||||||
];
|
];
|
||||||
|
|
||||||
$orderItemModel->insert($items);
|
$orderItemModel->insert($items);
|
||||||
@ -387,105 +388,144 @@ class Orders extends Model
|
|||||||
->findAll();
|
->findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPaymentModes()
|
public function getPaymentModes($startDate = null, $endDate = null, $storeId = null, $userId = null)
|
||||||
{
|
{
|
||||||
$session = session();
|
$session = session();
|
||||||
$users = $session->get('user');
|
$users = $session->get('user');
|
||||||
$isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
|
$isAdmin = in_array($users['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
|
||||||
|
|
||||||
$baseQuery = $this->db->table('orders')
|
$baseQuery = $this->db->table('orders')
|
||||||
->select('
|
->select('
|
||||||
|
|
||||||
SUM(CASE
|
SUM(CASE
|
||||||
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
||||||
THEN orders.discount
|
THEN orders.discount
|
||||||
ELSE orders.net_amount
|
ELSE orders.net_amount
|
||||||
END) AS total,
|
END) AS total,
|
||||||
|
|
||||||
|
|
||||||
SUM(CASE
|
SUM(CASE
|
||||||
WHEN orders.order_payment_mode = "MVOLA" THEN
|
WHEN orders.order_payment_mode = "MVOLA" THEN
|
||||||
CASE
|
CASE
|
||||||
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
||||||
THEN (orders.tranche_1 * orders.discount / orders.net_amount)
|
THEN (orders.tranche_1 * orders.discount / orders.net_amount)
|
||||||
ELSE orders.tranche_1
|
ELSE orders.tranche_1
|
||||||
END
|
END
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END) AS total_mvola1,
|
END) AS total_mvola1,
|
||||||
SUM(CASE
|
SUM(CASE
|
||||||
WHEN orders.order_payment_mode_1 = "MVOLA" THEN
|
WHEN orders.order_payment_mode_1 = "MVOLA" THEN
|
||||||
CASE
|
CASE
|
||||||
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
||||||
THEN (orders.tranche_2 * orders.discount / orders.net_amount)
|
THEN (orders.tranche_2 * orders.discount / orders.net_amount)
|
||||||
ELSE orders.tranche_2
|
ELSE orders.tranche_2
|
||||||
END
|
END
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END) AS total_mvola2,
|
END) AS total_mvola2,
|
||||||
|
|
||||||
|
|
||||||
SUM(CASE
|
SUM(CASE
|
||||||
WHEN orders.order_payment_mode = "En espèce" THEN
|
WHEN orders.order_payment_mode = "En espèce" THEN
|
||||||
CASE
|
CASE
|
||||||
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
||||||
THEN (orders.tranche_1 * orders.discount / orders.net_amount)
|
THEN (orders.tranche_1 * orders.discount / orders.net_amount)
|
||||||
ELSE orders.tranche_1
|
ELSE orders.tranche_1
|
||||||
END
|
END
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END) AS total_espece1,
|
END) AS total_espece1,
|
||||||
SUM(CASE
|
SUM(CASE
|
||||||
WHEN orders.order_payment_mode_1 = "En espèce" THEN
|
WHEN orders.order_payment_mode_1 = "En espèce" THEN
|
||||||
CASE
|
CASE
|
||||||
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
||||||
THEN (orders.tranche_2 * orders.discount / orders.net_amount)
|
THEN (orders.tranche_2 * orders.discount / orders.net_amount)
|
||||||
ELSE orders.tranche_2
|
ELSE orders.tranche_2
|
||||||
END
|
END
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END) AS total_espece2,
|
END) AS total_espece2,
|
||||||
|
|
||||||
|
|
||||||
SUM(CASE
|
SUM(CASE
|
||||||
WHEN orders.order_payment_mode = "Virement bancaire" THEN
|
WHEN orders.order_payment_mode = "Virement bancaire" THEN
|
||||||
CASE
|
CASE
|
||||||
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
||||||
THEN (orders.tranche_1 * orders.discount / orders.net_amount)
|
THEN (orders.tranche_1 * orders.discount / orders.net_amount)
|
||||||
ELSE orders.tranche_1
|
ELSE orders.tranche_1
|
||||||
END
|
END
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END) AS total_virement_bancaire1,
|
END) AS total_virement_bancaire1,
|
||||||
SUM(CASE
|
SUM(CASE
|
||||||
WHEN orders.order_payment_mode_1 = "Virement bancaire" THEN
|
WHEN orders.order_payment_mode_1 = "Virement bancaire" THEN
|
||||||
CASE
|
CASE
|
||||||
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
||||||
THEN (orders.tranche_2 * orders.discount / orders.net_amount)
|
THEN (orders.tranche_2 * orders.discount / orders.net_amount)
|
||||||
ELSE orders.tranche_2
|
ELSE orders.tranche_2
|
||||||
END
|
END
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END) AS total_virement_bancaire2
|
END) AS total_virement_bancaire2
|
||||||
')
|
')
|
||||||
->whereIn('orders.paid_status', [1, 3]);
|
->whereIn('orders.paid_status', [1, 3]);
|
||||||
|
|
||||||
if (!$isAdmin) {
|
if (!empty($storeId)) {
|
||||||
|
$baseQuery->where('orders.store_id', $storeId);
|
||||||
|
} elseif (!$isAdmin) {
|
||||||
$baseQuery->where('orders.store_id', $users['store_id']);
|
$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();
|
return $baseQuery->get()->getRowObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTotalOrders()
|
public function getTotalOrders($startDate = null, $endDate = null, $storeId = null, $userId = null)
|
||||||
{
|
{
|
||||||
return $this->db->table('orders')
|
$builder = $this->db->table('orders')
|
||||||
->select(' COUNT(*) as total_orders')
|
->select('COUNT(*) as total_orders');
|
||||||
->get()
|
|
||||||
->getRow();
|
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()->getRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTotalOrderPerStore()
|
public function getTotalOrderPerStore($startDate = null, $endDate = null, $storeId = null, $userId = null)
|
||||||
{
|
{
|
||||||
return $this->db->table('orders')
|
$builder = $this->db->table('orders')
|
||||||
->select('store_id, COUNT(*) as total')
|
->select('store_id, COUNT(*) as total')
|
||||||
->groupBy('store_id')
|
->groupBy('store_id');
|
||||||
->get()
|
|
||||||
->getResult();
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPaymentModesPercentage()
|
public function getPaymentModesPercentage()
|
||||||
@ -549,56 +589,60 @@ class Orders extends Model
|
|||||||
return $order;
|
return $order;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTotalProductvente2(?int $id)
|
public function getTotalProductvente2(?int $id, $startDate = null, $endDate = null)
|
||||||
{
|
{
|
||||||
|
$builder = $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) {
|
if ($id != 0) {
|
||||||
$order = $this->db->table('orders')
|
$builder->where('orders.store_id', $id);
|
||||||
->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
|
|
||||||
->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();
|
|
||||||
}
|
}
|
||||||
|
if (!empty($startDate)) {
|
||||||
return $order;
|
$builder->where('DATE(orders.date_time) >=', $startDate);
|
||||||
|
}
|
||||||
|
if (!empty($endDate)) {
|
||||||
|
$builder->where('DATE(orders.date_time) <=', $endDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $builder->get()->getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOrderVendue()
|
public function getOrderVendue($storeId = null, $startDate = null, $endDate = null)
|
||||||
{
|
{
|
||||||
$order = $this->db->table('products')
|
$builder = $this->db->table('products')
|
||||||
->select('
|
->select('
|
||||||
products.*,
|
products.*,
|
||||||
products.name as Pname,
|
products.name as Pname,
|
||||||
products.sku,
|
products.sku,
|
||||||
CASE
|
CASE
|
||||||
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
WHEN orders.discount > 0 AND orders.discount IS NOT NULL
|
||||||
THEN orders.discount
|
THEN orders.discount
|
||||||
ELSE orders.gross_amount
|
ELSE orders.gross_amount
|
||||||
END as totalNet,
|
END as totalNet,
|
||||||
orders.date_time as DateTime
|
orders.date_time as DateTime
|
||||||
', false) // ← MODIFIÉ ICI
|
', false)
|
||||||
->join('orders_item', 'products.id = orders_item.product_id')
|
->join('orders_item', 'products.id = orders_item.product_id')
|
||||||
->join('orders', 'orders_item.order_id = orders.id')
|
->join('orders', 'orders_item.order_id = orders.id')
|
||||||
->whereIn('orders.paid_status', [1, 3]) // ← ET ICI
|
->whereIn('orders.paid_status', [1, 3]);
|
||||||
->get()
|
|
||||||
->getResultArray();
|
if (!empty($storeId) && $storeId != 0) {
|
||||||
|
$builder->where('orders.store_id', $storeId);
|
||||||
return $order;
|
}
|
||||||
|
if (!empty($startDate)) {
|
||||||
|
$builder->where('DATE(orders.date_time) >=', $startDate);
|
||||||
|
}
|
||||||
|
if (!empty($endDate)) {
|
||||||
|
$builder->where('DATE(orders.date_time) <=', $endDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $builder->get()->getResultArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPerformanceByOrders($startDate = null, $endDate = null, $pvente = null)
|
public function getPerformanceByOrders($startDate = null, $endDate = null, $pvente = null, $commercialId = null)
|
||||||
{
|
{
|
||||||
$builder = $this->db->table('orders')
|
$builder = $this->db->table('orders')
|
||||||
->select('orders.id as orderid, orders.net_amount, orders.date_time as datevente, orders.discount, products.price, products.sku, products.prix_vente, products.name as motoname, stores.id as store_id, users.firstname, users.lastname, users.email')
|
->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')
|
||||||
@ -607,8 +651,7 @@ class Orders extends Model
|
|||||||
->join('products', 'products.id = orders_item.product_id')
|
->join('products', 'products.id = orders_item.product_id')
|
||||||
->join('users', 'users.id = orders.user_id')
|
->join('users', 'users.id = orders.user_id')
|
||||||
->whereIn('orders.paid_status', [1, 3]);
|
->whereIn('orders.paid_status', [1, 3]);
|
||||||
|
|
||||||
// ✅ AJOUT : FILTRES PAR DATE
|
|
||||||
if (!empty($startDate) && !empty($endDate)) {
|
if (!empty($startDate) && !empty($endDate)) {
|
||||||
$builder->where('DATE(orders.date_time) >=', $startDate);
|
$builder->where('DATE(orders.date_time) >=', $startDate);
|
||||||
$builder->where('DATE(orders.date_time) <=', $endDate);
|
$builder->where('DATE(orders.date_time) <=', $endDate);
|
||||||
@ -617,14 +660,17 @@ class Orders extends Model
|
|||||||
} elseif (!empty($endDate)) {
|
} elseif (!empty($endDate)) {
|
||||||
$builder->where('DATE(orders.date_time) <=', $endDate);
|
$builder->where('DATE(orders.date_time) <=', $endDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ AJOUT : FILTRE PAR POINT DE VENTE
|
|
||||||
if (!empty($pvente) && $pvente !== 'TOUS') {
|
if (!empty($pvente) && $pvente !== 'TOUS') {
|
||||||
$builder->where('stores.name', $pvente);
|
$builder->where('stores.name', $pvente);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($commercialId) && $commercialId !== 'TOUS') {
|
||||||
|
$builder->where('orders.user_id', $commercialId);
|
||||||
|
}
|
||||||
|
|
||||||
$builder->orderBy('orders.date_time', 'DESC');
|
$builder->orderBy('orders.date_time', 'DESC');
|
||||||
|
|
||||||
return $builder->get()->getResultArray();
|
return $builder->get()->getResultArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,8 +21,8 @@ class Products extends Model
|
|||||||
$isAdmin = in_array($user['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
|
$isAdmin = in_array($user['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
|
||||||
|
|
||||||
$builder = $this->where('is_piece', 0)
|
$builder = $this->where('is_piece', 0)
|
||||||
->where('product_sold', 0);
|
->whereIn('product_sold', [0, 2]);
|
||||||
|
|
||||||
if (!$isAdmin) {
|
if (!$isAdmin) {
|
||||||
if (empty($user['store_id']) || $user['store_id'] == 0) {
|
if (empty($user['store_id']) || $user['store_id'] == 0) {
|
||||||
$builder->where('id', -1);
|
$builder->where('id', -1);
|
||||||
@ -58,11 +58,27 @@ class Products extends Model
|
|||||||
|
|
||||||
return $builder->join('brands', 'brands.id = products.marque')
|
return $builder->join('brands', 'brands.id = products.marque')
|
||||||
->orderBy('products.id', 'DESC')
|
->orderBy('products.id', 'DESC')
|
||||||
->select('brands.name as brand_name,COUNT( products.id) as total_product, products.store_id as store_id,products.*')
|
->select('brands.name as brand_name, products.store_id as store_id, products.*')
|
||||||
->groupBy('store_id')
|
|
||||||
->findAll();
|
->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)
|
public function getProductData3(int $id)
|
||||||
{
|
{
|
||||||
if ($id == 0) {
|
if ($id == 0) {
|
||||||
@ -75,7 +91,7 @@ class Products extends Model
|
|||||||
public function getProductDataStore(int $store_id, bool $excludeAvance = true, int $currentProductId = null)
|
public function getProductDataStore(int $store_id, bool $excludeAvance = true, int $currentProductId = null)
|
||||||
{
|
{
|
||||||
$builder = $this->where('is_piece', 0)
|
$builder = $this->where('is_piece', 0)
|
||||||
->where('product_sold', 0)
|
->whereIn('product_sold', [0, 2])
|
||||||
->where('availability', 1)
|
->where('availability', 1)
|
||||||
->where('store_id', $store_id);
|
->where('store_id', $store_id);
|
||||||
|
|
||||||
@ -92,13 +108,14 @@ class Products extends Model
|
|||||||
$builder->where("id NOT IN ($subQueryAvances)", null, false);
|
$builder->where("id NOT IN ($subQueryAvances)", null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ LISTE : Exclure TOUS les produits ayant une commande (statuts 1, 2, 3)
|
// ✅ 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
|
||||||
$subQueryOrders = $db->table('orders_item')
|
$subQueryOrders = $db->table('orders_item')
|
||||||
->select('orders_item.product_id')
|
->select('orders_item.product_id')
|
||||||
->join('orders', 'orders.id = orders_item.order_id')
|
->join('orders', 'orders.id = orders_item.order_id')
|
||||||
->whereIn('orders.paid_status', [1, 2, 3]) // ✅ Disparaît de la liste dès qu'il y a une commande
|
->where('orders.paid_status', 3)
|
||||||
->getCompiledSelect();
|
->getCompiledSelect();
|
||||||
|
|
||||||
$builder->where("id NOT IN ($subQueryOrders)", null, false);
|
$builder->where("id NOT IN ($subQueryOrders)", null, false);
|
||||||
|
|
||||||
// Exception pour le produit actuel lors de modification de commande
|
// Exception pour le produit actuel lors de modification de commande
|
||||||
|
|||||||
@ -16,10 +16,9 @@ class Remise extends Model
|
|||||||
$session = session();
|
$session = session();
|
||||||
$users = $session->get('user');
|
$users = $session->get('user');
|
||||||
|
|
||||||
// ✅ SUPERADMIN VOIT TOUTES LES DEMANDES "EN ATTENTE" (POUR VALIDATION)
|
// ✅ SUPERADMIN VOIT TOUTES LES DEMANDES (TOUS STATUTS)
|
||||||
if ($users["group_name"] === "SuperAdmin") {
|
if ($users["group_name"] === "SuperAdmin") {
|
||||||
return $this->where('demande_status', 'En attente')
|
return $this->orderBy('date_demande', 'DESC')
|
||||||
->orderBy('date_demande', 'DESC')
|
|
||||||
->findAll();
|
->findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,37 +39,51 @@ class Reports extends Model
|
|||||||
* @param mixed $year
|
* @param mixed $year
|
||||||
* @return array<array>
|
* @return array<array>
|
||||||
*/
|
*/
|
||||||
public function getOrderData($year)
|
public function getOrderData($year, $startDate = null, $endDate = null, $storeId = null, $userId = null)
|
||||||
{
|
{
|
||||||
if ($year) {
|
if ($year) {
|
||||||
$months = $this->months();
|
$months = $this->months();
|
||||||
|
|
||||||
// Fetch orders with paid_status = 1 or 3
|
// Fetch orders with paid_status = 1 or 3
|
||||||
$result = $this->whereIn('paid_status', [1, 3])->findAll();
|
$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();
|
||||||
|
|
||||||
$final_data = [];
|
$final_data = [];
|
||||||
|
|
||||||
foreach ($months as $month) {
|
foreach ($months as $month) {
|
||||||
$get_mon_year = $year . '-' . $month;
|
$get_mon_year = $year . '-' . $month;
|
||||||
$final_data[$get_mon_year] = [];
|
$final_data[$get_mon_year] = [];
|
||||||
|
|
||||||
foreach ($result as $v) {
|
foreach ($result as $v) {
|
||||||
$month_year = date('Y-m', strtotime($v['date_time']));
|
$month_year = date('Y-m', strtotime($v['date_time']));
|
||||||
if ($get_mon_year == $month_year) {
|
if ($get_mon_year == $month_year) {
|
||||||
// Modifier le montant selon votre logique
|
|
||||||
if (!empty($v['discount']) && $v['discount'] > 0) {
|
if (!empty($v['discount']) && $v['discount'] > 0) {
|
||||||
$v['amount_to_display'] = $v['discount']; // Utiliser le rabais
|
$v['amount_to_display'] = $v['discount'];
|
||||||
} else {
|
} else {
|
||||||
$v['amount_to_display'] = $v['gross_amount']; // Utiliser gross_amount
|
$v['amount_to_display'] = $v['gross_amount'];
|
||||||
}
|
}
|
||||||
$final_data[$get_mon_year][] = $v;
|
$final_data[$get_mon_year][] = $v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $final_data;
|
return $final_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12,7 +12,7 @@ class Securite extends Model
|
|||||||
*/
|
*/
|
||||||
protected $table = 'securite';
|
protected $table = 'securite';
|
||||||
protected $primaryKey = 'id'; // Primary key column
|
protected $primaryKey = 'id'; // Primary key column
|
||||||
protected $allowedFields = ['product_id', 'status', 'date', 'active'];
|
protected $allowedFields = ['product_id', 'bill_no', 'store_id', 'status', 'date', 'active'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -165,25 +165,24 @@ class SortieCaisse extends Model
|
|||||||
/**
|
/**
|
||||||
* ✅ MODIFICATION : DAF, Direction, SuperAdmin voient TOUS les totaux
|
* ✅ MODIFICATION : DAF, Direction, SuperAdmin voient TOUS les totaux
|
||||||
*/
|
*/
|
||||||
public function getTotalSortieCaisse() {
|
public function getTotalSortieCaisse($startDate = null, $endDate = null) {
|
||||||
$session = session();
|
$session = session();
|
||||||
$users = $session->get('user');
|
$users = $session->get('user');
|
||||||
|
|
||||||
// ✅ DAF, Direction, SuperAdmin : Voir TOUS les stores
|
|
||||||
$isAdmin = in_array($users['group_name'], ['Direction', 'DAF', 'SuperAdmin']);
|
$isAdmin = in_array($users['group_name'], ['Direction', 'DAF', 'SuperAdmin']);
|
||||||
|
|
||||||
if ($isAdmin) {
|
if ($isAdmin) {
|
||||||
try {
|
try {
|
||||||
return $this->select('
|
$builder = $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 = "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 = "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 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
|
SUM(CASE WHEN statut = "Payé" THEN montant_retire ELSE 0 END) AS mr
|
||||||
')
|
')
|
||||||
// ✅ CHANGEMENT : Uniquement statut = "Payé" (plus "Valider")
|
->where('statut', 'Payé');
|
||||||
->where('statut', 'Payé')
|
if ($startDate) { $builder->where('DATE(created_at) >=', $startDate); }
|
||||||
->get()
|
if ($endDate) { $builder->where('DATE(created_at) <=', $endDate); }
|
||||||
->getRowObject();
|
return $builder->get()->getRowObject();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
log_message('error', 'Erreur getTotalSortieCaisse (Admin) : ' . $e->getMessage());
|
log_message('error', 'Erreur getTotalSortieCaisse (Admin) : ' . $e->getMessage());
|
||||||
return (object)[
|
return (object)[
|
||||||
@ -194,19 +193,18 @@ class SortieCaisse extends Model
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ✅ CAISSIÈRE : Uniquement son store ET statut "Payé"
|
|
||||||
try {
|
try {
|
||||||
return $this->select('
|
$builder = $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 = "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 = "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 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
|
SUM(CASE WHEN statut = "Payé" THEN montant_retire ELSE 0 END) AS mr
|
||||||
')
|
')
|
||||||
->where('store_id', $users['store_id'])
|
->where('store_id', $users['store_id'])
|
||||||
// ✅ CHANGEMENT : Uniquement statut = "Payé" (plus "Valider")
|
->where('statut', 'Payé');
|
||||||
->where('statut', 'Payé')
|
if ($startDate) { $builder->where('DATE(created_at) >=', $startDate); }
|
||||||
->get()
|
if ($endDate) { $builder->where('DATE(created_at) <=', $endDate); }
|
||||||
->getRowObject();
|
return $builder->get()->getRowObject();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
log_message('error', 'Erreur getTotalSortieCaisse (Store) : ' . $e->getMessage());
|
log_message('error', 'Erreur getTotalSortieCaisse (Store) : ' . $e->getMessage());
|
||||||
return (object)[
|
return (object)[
|
||||||
|
|||||||
178
app/Views/action_log/index.php
Normal file
178
app/Views/action_log/index.php
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
<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,12 +42,16 @@ $isCaissier = isset($users['group_name']) && in_array($users['group_name'], ['Ca
|
|||||||
|
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<button id="avance_no_order" class="btn btn-info w-100 rounded-pill shadow-sm py-2">
|
<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> Avances Incomplètes
|
<i class="fa fa-hourglass-half me-2"></i>
|
||||||
|
<span class="badge badge-light" id="incomplete-count">0</span>
|
||||||
|
Avances Incomplètes
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<button id="avance_order" class="btn btn-success w-100 rounded-pill shadow-sm py-2">
|
<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> Avances Complètes
|
<i class="fa fa-check-circle me-2"></i>
|
||||||
|
<span class="badge badge-light" id="complete-count">0</span>
|
||||||
|
Avances Complètes
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
@ -82,6 +86,7 @@ $isCaissier = isset($users['group_name']) && in_array($users['group_name'], ['Ca
|
|||||||
<th>Téléphone</th>
|
<th>Téléphone</th>
|
||||||
<th>Adresse</th>
|
<th>Adresse</th>
|
||||||
<th>Produit</th>
|
<th>Produit</th>
|
||||||
|
<th>N° Série</th>
|
||||||
<th>Prix</th>
|
<th>Prix</th>
|
||||||
<th>Avance</th>
|
<th>Avance</th>
|
||||||
<th>Reste à payer</th>
|
<th>Reste à payer</th>
|
||||||
@ -91,11 +96,12 @@ $isCaissier = isset($users['group_name']) && in_array($users['group_name'], ['Ca
|
|||||||
<?php endif;?>
|
<?php endif;?>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endif;?>
|
<?php endif;?>
|
||||||
|
|
||||||
<?php if ($isCommerciale || $isCaissier): ?>
|
<?php if ($isCommerciale || $isCaissier): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
<th>Produit</th>
|
<th>Produit</th>
|
||||||
|
<th>N° Série</th>
|
||||||
<th>Avance</th>
|
<th>Avance</th>
|
||||||
<th>Reste à payer</th>
|
<th>Reste à payer</th>
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
@ -500,6 +506,38 @@ $(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
|
// Variables de rôles
|
||||||
var isCaissier = <?php echo json_encode($isCaissier ?? false); ?>;
|
var isCaissier = <?php echo json_encode($isCaissier ?? false); ?>;
|
||||||
var isCommerciale = <?php echo json_encode($isCommerciale ?? false); ?>;
|
var isCommerciale = <?php echo json_encode($isCommerciale ?? false); ?>;
|
||||||
@ -516,19 +554,20 @@ $(document).ready(function() {
|
|||||||
{ title: "Téléphone" },
|
{ title: "Téléphone" },
|
||||||
{ title: "Adresse" },
|
{ title: "Adresse" },
|
||||||
{ title: "Produit" },
|
{ title: "Produit" },
|
||||||
{
|
{ title: "N° Série" },
|
||||||
|
{
|
||||||
title: "Prix",
|
title: "Prix",
|
||||||
render: function(data, type, row) {
|
render: function(data, type, row) {
|
||||||
return type === 'display' ? formatNumber(data) : data;
|
return type === 'display' ? formatNumber(data) : data;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Avance",
|
title: "Avance",
|
||||||
render: function(data, type, row) {
|
render: function(data, type, row) {
|
||||||
return type === 'display' ? formatNumber(data) : data;
|
return type === 'display' ? formatNumber(data) : data;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Reste à payer",
|
title: "Reste à payer",
|
||||||
render: function(data, type, row) {
|
render: function(data, type, row) {
|
||||||
return type === 'display' ? formatNumber(data) : data;
|
return type === 'display' ? formatNumber(data) : data;
|
||||||
@ -542,14 +581,43 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
var manageTable = initAvanceTable(base_url + 'avances/fetchAvanceData', adminColumns);
|
var manageTable = initAvanceTable(base_url + 'avances/fetchAvanceData', adminColumns);
|
||||||
|
|
||||||
|
// Charger les compteurs
|
||||||
|
loadAvanceCounts();
|
||||||
|
setInterval(loadAvanceCounts, 30000);
|
||||||
|
|
||||||
$('#avance_no_order').on('click', function() {
|
$('#avance_no_order').on('click', function() {
|
||||||
$('#table-title').text('Avances Incomplètes');
|
$('#table-title').text('Avances Incomplètes');
|
||||||
manageTable = initAvanceTable(base_url + 'avances/fetchAvanceData', adminColumns);
|
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() {
|
$('#avance_order').on('click', function() {
|
||||||
$('#table-title').text('Avances Complètes');
|
$('#table-title').text('Avances Complètes');
|
||||||
manageTable = initAvanceTable(base_url + 'avances/fetchAvanceBecameOrder', adminColumns);
|
manageTable = initAvanceTable(base_url + 'avances/fetchAvanceBecameOrder', adminCompletedColumns);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#avance_expired').on('click', function() {
|
$('#avance_expired').on('click', function() {
|
||||||
@ -563,7 +631,8 @@ $(document).ready(function() {
|
|||||||
var userColumns = [
|
var userColumns = [
|
||||||
{ title: "#" },
|
{ title: "#" },
|
||||||
{ title: "Produit" },
|
{ title: "Produit" },
|
||||||
{
|
{ title: "N° Série" },
|
||||||
|
{
|
||||||
title: "Avance",
|
title: "Avance",
|
||||||
render: function(data, type, row) {
|
render: function(data, type, row) {
|
||||||
return type === 'display' ? formatNumber(data) : data;
|
return type === 'display' ? formatNumber(data) : data;
|
||||||
@ -593,12 +662,13 @@ $(document).ready(function() {
|
|||||||
$('#avanceTable').DataTable().destroy();
|
$('#avanceTable').DataTable().destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ Reconstruire les headers (format caissière/commercial)
|
// Reconstruire les headers (format caissière/commercial)
|
||||||
rebuildTableHeaders([
|
rebuildTableHeaders([
|
||||||
'#',
|
'#',
|
||||||
'Produit',
|
'Produit',
|
||||||
'Avance',
|
'N° Série',
|
||||||
'Reste à payer',
|
'Avance',
|
||||||
|
'Reste à payer',
|
||||||
'Date',
|
'Date',
|
||||||
'Action'
|
'Action'
|
||||||
]);
|
]);
|
||||||
@ -627,21 +697,34 @@ $('#avance_order').on('click', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rebuildTableHeaders([
|
rebuildTableHeaders([
|
||||||
'#',
|
'#',
|
||||||
'Produit',
|
'Produit',
|
||||||
'Avance',
|
'N° Série',
|
||||||
'Reste à payer',
|
'Avance',
|
||||||
|
'Statut',
|
||||||
'Date',
|
'Date',
|
||||||
'Action'
|
'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({
|
manageTable = $('#avanceTable').DataTable({
|
||||||
ajax: {
|
ajax: {
|
||||||
url: base_url + 'avances/fetchAvanceBecameOrder',
|
url: base_url + 'avances/fetchAvanceBecameOrder',
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
dataSrc: 'data'
|
dataSrc: 'data'
|
||||||
},
|
},
|
||||||
columns: userColumns,
|
columns: completedUserColumns,
|
||||||
language: datatableLangFr
|
language: datatableLangFr
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -658,14 +741,15 @@ $('#avance_expired').on('click', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rebuildTableHeaders([
|
rebuildTableHeaders([
|
||||||
'#',
|
'#',
|
||||||
'Produit',
|
'Produit',
|
||||||
'Avance',
|
'N° Série',
|
||||||
'Reste à payer',
|
'Avance',
|
||||||
|
'Reste à payer',
|
||||||
'Date',
|
'Date',
|
||||||
'Action'
|
'Action'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
manageTable = $('#avanceTable').DataTable({
|
manageTable = $('#avanceTable').DataTable({
|
||||||
ajax: {
|
ajax: {
|
||||||
url: base_url + 'avances/fetchExpiredAvance',
|
url: base_url + 'avances/fetchExpiredAvance',
|
||||||
@ -679,8 +763,10 @@ $('#avance_expired').on('click', function() {
|
|||||||
console.log('✅ DataTable Expirées initialisée');
|
console.log('✅ DataTable Expirées initialisée');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Charger le compteur d'avances en attente
|
// Charger les compteurs d'avances
|
||||||
loadPendingCount();
|
loadPendingCount();
|
||||||
|
loadAvanceCounts();
|
||||||
|
setInterval(loadAvanceCounts, 30000);
|
||||||
setInterval(loadPendingCount, 30000);
|
setInterval(loadPendingCount, 30000);
|
||||||
|
|
||||||
console.log('✅ Module caissière initialisé');
|
console.log('✅ Module caissière initialisé');
|
||||||
@ -1547,18 +1633,17 @@ window.validateAvanceFunc = function(avance_id) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// 🔥 CHARGER COMPTEUR AVANCES EN ATTENTE
|
// CHARGER COMPTEURS AVANCES
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
|
||||||
function loadPendingCount() {
|
function loadPendingCount() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: base_url + 'avances/fetchPendingValidation',
|
url: base_url + 'avances/fetchPendingValidation',
|
||||||
type: 'POST', // ✅ CORRECTION
|
type: 'POST',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
var count = response.data ? response.data.length : 0;
|
var count = response.data ? response.data.length : 0;
|
||||||
$('#pending-count').text(count);
|
$('#pending-count').text(count);
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
$('#pending-count').removeClass('badge-light').addClass('badge-danger');
|
$('#pending-count').removeClass('badge-light').addClass('badge-danger');
|
||||||
$('#avance_pending').addClass('btn-pulse');
|
$('#avance_pending').addClass('btn-pulse');
|
||||||
@ -1566,13 +1651,12 @@ function loadPendingCount() {
|
|||||||
$('#pending-count').removeClass('badge-danger').addClass('badge-light');
|
$('#pending-count').removeClass('badge-danger').addClass('badge-light');
|
||||||
$('#avance_pending').removeClass('btn-pulse');
|
$('#avance_pending').removeClass('btn-pulse');
|
||||||
}
|
}
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
console.error('Erreur chargement compteur avances en attente');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadAvanceCounts defini plus haut
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// 🔥 TRAITER AVANCES EXPIRÉES (ADMIN)
|
// 🔥 TRAITER AVANCES EXPIRÉES (ADMIN)
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
<th>Prix</th>
|
<th>Prix</th>
|
||||||
<th>Puissances</th>
|
<th>Puissances</th>
|
||||||
<th>N° Moteur</th>
|
<th>N° Moteur</th>
|
||||||
|
<th>Disponibilité</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -72,10 +73,15 @@ $.extend(true, $.fn.dataTable.defaults, {
|
|||||||
'ajax': `<?= base_url('ventes/fetchProductVente') ?>/${id}`,
|
'ajax': `<?= base_url('ventes/fetchProductVente') ?>/${id}`,
|
||||||
'order': [],
|
'order': [],
|
||||||
'columnDefs': [{
|
'columnDefs': [{
|
||||||
targets: 6,
|
targets: 7,
|
||||||
className: 'text-right'
|
className: 'text-right'
|
||||||
} // Column index 3 corresponds to "Prix"
|
}
|
||||||
]
|
],
|
||||||
|
'createdRow': function(row, data, dataIndex) {
|
||||||
|
if (data[6] && data[6].indexOf('En attente de livraison') !== -1) {
|
||||||
|
$(row).css({'background-color': '#fff3cd', 'opacity': '0.85'});
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
<div class="box-header">
|
<div class="box-header">
|
||||||
<h3 class="box-title">Gérer les informations sur l'entreprise</h3>
|
<h3 class="box-title">Gérer les informations sur l'entreprise</h3>
|
||||||
</div>
|
</div>
|
||||||
<form role="form" action="<?php base_url('company/update') ?>" method="post">
|
<form role="form" action="<?php base_url('company/update') ?>" method="post" enctype="multipart/form-data">
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
|
|
||||||
<!-- Validation errors -->
|
<!-- Validation errors -->
|
||||||
@ -48,6 +48,19 @@
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?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">
|
<div class="form-group">
|
||||||
<label for="company_name">Nom de l'entreprise</label>
|
<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">
|
<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,6 +311,13 @@
|
|||||||
<h3 class="box-title">
|
<h3 class="box-title">
|
||||||
<i class="fa fa-calculator"></i> Résumé de Trésorerie
|
<i class="fa fa-calculator"></i> Résumé de Trésorerie
|
||||||
</h3>
|
</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>
|
||||||
|
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
@ -320,7 +327,7 @@
|
|||||||
<div class="col-sm-3 col-xs-12">
|
<div class="col-sm-3 col-xs-12">
|
||||||
<div class="amount-block brut">
|
<div class="amount-block brut">
|
||||||
<span class="amount-label" style="color: #388e3c;">💰 Total Brut</span>
|
<span class="amount-label" style="color: #388e3c;">💰 Total Brut</span>
|
||||||
<div class="amount-header" style="color: #2e7d32;">
|
<div class="amount-header" style="color: #2e7d32;" id="treso-brut">
|
||||||
<?php echo number_format($total_brut, 0, '.', ' '); ?> Ar
|
<?php echo number_format($total_brut, 0, '.', ' '); ?> Ar
|
||||||
</div>
|
</div>
|
||||||
<span class="amount-sublabel">Orders + Avances</span>
|
<span class="amount-sublabel">Orders + Avances</span>
|
||||||
@ -336,7 +343,7 @@
|
|||||||
<div class="col-sm-3 col-xs-12">
|
<div class="col-sm-3 col-xs-12">
|
||||||
<div class="amount-block sorties">
|
<div class="amount-block sorties">
|
||||||
<span class="amount-label" style="color: #c62828;">💸 Décaissements</span>
|
<span class="amount-label" style="color: #c62828;">💸 Décaissements</span>
|
||||||
<div class="amount-header" style="color: #d32f2f;">
|
<div class="amount-header" style="color: #d32f2f;" id="treso-sorties">
|
||||||
<?php echo number_format($total_sorties, 0, '.', ' '); ?> Ar
|
<?php echo number_format($total_sorties, 0, '.', ' '); ?> Ar
|
||||||
</div>
|
</div>
|
||||||
<span class="amount-sublabel">Espèce + MVOLA + Virement</span>
|
<span class="amount-sublabel">Espèce + MVOLA + Virement</span>
|
||||||
@ -352,7 +359,7 @@
|
|||||||
<div class="col-sm-4 col-xs-12">
|
<div class="col-sm-4 col-xs-12">
|
||||||
<div class="amount-block net">
|
<div class="amount-block net">
|
||||||
<span class="amount-label" style="color: #1565c0;">✅ Solde Net</span>
|
<span class="amount-label" style="color: #1565c0;">✅ Solde Net</span>
|
||||||
<div class="amount-header" style="color: #1976d2; font-size: 36px;">
|
<div class="amount-header" style="color: #1976d2; font-size: 36px;" id="treso-net">
|
||||||
<?php echo number_format($total_caisse, 0, '.', ' '); ?> Ar
|
<?php echo number_format($total_caisse, 0, '.', ' '); ?> Ar
|
||||||
</div>
|
</div>
|
||||||
<span class="amount-sublabel">Disponible en caisse</span>
|
<span class="amount-sublabel">Disponible en caisse</span>
|
||||||
@ -371,10 +378,10 @@
|
|||||||
<div class="payment-icon espece">
|
<div class="payment-icon espece">
|
||||||
<i class="fa fa-money"></i>
|
<i class="fa fa-money"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="payment-amount">
|
<div class="payment-amount" id="treso-espece">
|
||||||
<?php echo number_format($total_espece_caisse, 0, '.', ' '); ?> Ar
|
<?php echo number_format($total_espece_caisse, 0, '.', ' '); ?> Ar
|
||||||
</div>
|
</div>
|
||||||
<div class="payment-label">💵 Espèce Disponible</div>
|
<div class="payment-label">Espece Disponible</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -384,10 +391,10 @@
|
|||||||
<div class="payment-icon mvola">
|
<div class="payment-icon mvola">
|
||||||
<i class="fa fa-mobile"></i>
|
<i class="fa fa-mobile"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="payment-amount">
|
<div class="payment-amount" id="treso-mvola">
|
||||||
<?php echo number_format($total_mvola_caisse, 0, '.', ' '); ?> Ar
|
<?php echo number_format($total_mvola_caisse, 0, '.', ' '); ?> Ar
|
||||||
</div>
|
</div>
|
||||||
<div class="payment-label">📱 MVOLA Disponible</div>
|
<div class="payment-label">MVOLA Disponible</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -397,10 +404,10 @@
|
|||||||
<div class="payment-icon banque">
|
<div class="payment-icon banque">
|
||||||
<i class="fa fa-bank"></i>
|
<i class="fa fa-bank"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="payment-amount">
|
<div class="payment-amount" id="treso-banque">
|
||||||
<?php echo number_format($total_vb_caisse, 0, '.', ' '); ?> Ar
|
<?php echo number_format($total_vb_caisse, 0, '.', ' '); ?> Ar
|
||||||
</div>
|
</div>
|
||||||
<div class="payment-label">🏦 Banque Disponible</div>
|
<div class="payment-label">Banque Disponible</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -408,6 +415,48 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</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 -->
|
<!-- Détail des avances par mode de paiement -->
|
||||||
<div class="container-fluid row" style="margin-top: 10px; margin-bottom: 20px;">
|
<div class="container-fluid row" style="margin-top: 10px; margin-bottom: 20px;">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
@ -419,19 +468,19 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="description-block">
|
<div class="description-block">
|
||||||
<h5 class="description-header"><?php echo number_format($total_avances_mvola, 0, '.', ' '); ?> Ar</h5>
|
<h5 class="description-header" id="avance-mvola"><?php echo number_format($total_avances_mvola, 0, '.', ' '); ?> Ar</h5>
|
||||||
<span class="description-text">MVOLA</span>
|
<span class="description-text">MVOLA</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="description-block">
|
<div class="description-block">
|
||||||
<h5 class="description-header"><?php echo number_format($total_avances_espece, 0, '.', ' '); ?> Ar</h5>
|
<h5 class="description-header" id="avance-espece"><?php echo number_format($total_avances_espece, 0, '.', ' '); ?> Ar</h5>
|
||||||
<span class="description-text">ESPÈCE</span>
|
<span class="description-text">ESPECE</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="description-block">
|
<div class="description-block">
|
||||||
<h5 class="description-header"><?php echo number_format($total_avances_virement, 0, '.', ' '); ?> Ar</h5>
|
<h5 class="description-header" id="avance-banque"><?php echo number_format($total_avances_virement, 0, '.', ' '); ?> Ar</h5>
|
||||||
<span class="description-text">BANQUE</span>
|
<span class="description-text">BANQUE</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -149,28 +149,27 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Recouvrement</td>
|
<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="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="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><input type="checkbox" name="permission[]" id="permission" value="deleteRecouvrement" class="minimal"></td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Décaissement</td>
|
<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="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="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="deleteSortieCaisse" class="minimal"></td>
|
||||||
<td><input type="checkbox" name="permission[]" id="permission" value="validateSortieCaisse" class="minimal"></td>
|
<td><input type="checkbox" name="permission[]" id="permission" value="validateSortieCaisse" class="minimal"></td>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Remise</td>
|
<td>Remise</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>
|
<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="refusedRemise" class="minimal"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Validation commande</td>
|
<td>Validation commande</td>
|
||||||
@ -181,11 +180,11 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Securité</td>
|
<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="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="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><input type="checkbox" name="permission[]" id="permission" value="deleteSecurite" class="minimal"></td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Rapports</td>
|
<td>Rapports</td>
|
||||||
@ -197,11 +196,11 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Avances</td>
|
<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="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="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><input type="checkbox" name="permission[]" id="permission" value="deleteAvance" class="minimal"></td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Entreprise</td>
|
<td>Entreprise</td>
|
||||||
|
|||||||
@ -75,6 +75,7 @@
|
|||||||
<th>Voir</th>
|
<th>Voir</th>
|
||||||
<th>Supprimer</th>
|
<th>Supprimer</th>
|
||||||
<th>Assigner</th>
|
<th>Assigner</th>
|
||||||
|
<th>Notification</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -96,6 +97,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Utilisateurs</td>
|
<td>Utilisateurs</td>
|
||||||
@ -140,6 +142,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>></td>
|
?>></td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Rôle</td>
|
<td>Rôle</td>
|
||||||
@ -176,6 +179,7 @@
|
|||||||
}
|
}
|
||||||
?>></td>
|
?>></td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Marques</td>
|
<td>Marques</td>
|
||||||
@ -204,6 +208,7 @@
|
|||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Categories</td>
|
<td>Categories</td>
|
||||||
@ -236,6 +241,7 @@
|
|||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Point de ventes</td>
|
<td>Point de ventes</td>
|
||||||
@ -269,6 +275,7 @@
|
|||||||
echo "checked";
|
echo "checked";
|
||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<td>Mécanicien</td>
|
<td>Mécanicien</td>
|
||||||
@ -305,6 +312,7 @@
|
|||||||
} ?>>
|
} ?>>
|
||||||
</td>
|
</td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Attributs</td>
|
<td>Attributs</td>
|
||||||
@ -337,6 +345,7 @@
|
|||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Produits</td>
|
<td>Produits</td>
|
||||||
@ -368,6 +377,12 @@
|
|||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></td>
|
||||||
<td>-</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>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Commandes</td>
|
<td>Commandes</td>
|
||||||
@ -396,15 +411,15 @@
|
|||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
</tr>
|
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="notifCommande"
|
||||||
<tr>
|
|
||||||
<td>Recouvrement</td>
|
|
||||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="viewRecouvrement"
|
|
||||||
<?php if ($serialize_permission) {
|
<?php if ($serialize_permission) {
|
||||||
if (in_array('viewRecouvrement', $serialize_permission)) {
|
if (in_array('notifCommande', $serialize_permission)) {
|
||||||
echo "checked";
|
echo "checked";
|
||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Recouvrement</td>
|
||||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="createRecouvrement"
|
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="createRecouvrement"
|
||||||
<?php if ($serialize_permission) {
|
<?php if ($serialize_permission) {
|
||||||
if (in_array('createRecouvrement', $serialize_permission)) {
|
if (in_array('createRecouvrement', $serialize_permission)) {
|
||||||
@ -417,6 +432,12 @@
|
|||||||
echo "checked";
|
echo "checked";
|
||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></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"
|
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="deleteRecouvrement"
|
||||||
<?php if ($serialize_permission) {
|
<?php if ($serialize_permission) {
|
||||||
if (in_array('deleteRecouvrement', $serialize_permission)) {
|
if (in_array('deleteRecouvrement', $serialize_permission)) {
|
||||||
@ -424,16 +445,16 @@
|
|||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></td>
|
||||||
<td>-</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>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>Sortie caisse</td>
|
<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"
|
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="createSortieCaisse"
|
||||||
<?php if ($serialize_permission) {
|
<?php if ($serialize_permission) {
|
||||||
if (in_array('createSortieCaisse', $serialize_permission)) {
|
if (in_array('createSortieCaisse', $serialize_permission)) {
|
||||||
@ -446,6 +467,12 @@
|
|||||||
echo "checked";
|
echo "checked";
|
||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></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"
|
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="deleteSortieCaisse"
|
||||||
<?php if ($serialize_permission) {
|
<?php if ($serialize_permission) {
|
||||||
if (in_array('deleteSortieCaisse', $serialize_permission)) {
|
if (in_array('deleteSortieCaisse', $serialize_permission)) {
|
||||||
@ -458,6 +485,12 @@
|
|||||||
echo "checked";
|
echo "checked";
|
||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></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>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Autres encaissements</td>
|
<td>Autres encaissements</td>
|
||||||
@ -484,28 +517,43 @@
|
|||||||
if (in_array('deleteEncaissement', $serialize_permission)) {
|
if (in_array('deleteEncaissement', $serialize_permission)) {
|
||||||
echo "checked";
|
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>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Remise</td>
|
<td>Remise</td>
|
||||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="viewRemise"
|
<td>-</td>
|
||||||
<?php if ($serialize_permission) {
|
|
||||||
if (in_array('viewRemise', $serialize_permission)) {
|
|
||||||
echo "checked";
|
|
||||||
}
|
|
||||||
} ?>></td>
|
|
||||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="validateRemise"
|
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="validateRemise"
|
||||||
<?php if ($serialize_permission) {
|
<?php if ($serialize_permission) {
|
||||||
if (in_array('validateRemise', $serialize_permission)) {
|
if (in_array('validateRemise', $serialize_permission)) {
|
||||||
echo "checked";
|
echo "checked";
|
||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></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="refusedRemise"
|
||||||
<?php if ($serialize_permission) {
|
<?php if ($serialize_permission) {
|
||||||
if (in_array('refusedRemise', $serialize_permission)) {
|
if (in_array('refusedRemise', $serialize_permission)) {
|
||||||
echo "checked";
|
echo "checked";
|
||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></td>
|
||||||
|
<td>-</td>
|
||||||
|
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="notifRemise"
|
||||||
|
<?php if ($serialize_permission) {
|
||||||
|
if (in_array('notifRemise', $serialize_permission)) {
|
||||||
|
echo "checked";
|
||||||
|
}
|
||||||
|
} ?>></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Validation Commande</td>
|
<td>Validation Commande</td>
|
||||||
@ -521,13 +569,15 @@
|
|||||||
echo "checked";
|
echo "checked";
|
||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></td>
|
||||||
|
<td>-</td>
|
||||||
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="deleteCommande1"
|
<td><input type="checkbox" name="permission[]" id="permission" class="minimal" value="deleteCommande1"
|
||||||
<?php if ($serialize_permission) {
|
<?php if ($serialize_permission) {
|
||||||
if (in_array('deleteCommande1', $serialize_permission)) {
|
if (in_array('deleteCommande1', $serialize_permission)) {
|
||||||
echo "checked";
|
echo "checked";
|
||||||
}
|
}
|
||||||
} ?>></td>
|
} ?>></td>
|
||||||
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Sécurité</td>
|
<td>Sécurité</td>
|
||||||
@ -557,6 +607,13 @@
|
|||||||
echo "checked";
|
echo "checked";
|
||||||
}
|
}
|
||||||
} ?>> </td>
|
} ?>> </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>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
@ -587,6 +644,13 @@
|
|||||||
echo "checked";
|
echo "checked";
|
||||||
}
|
}
|
||||||
} ?>> </td>
|
} ?>> </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>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
@ -601,6 +665,7 @@
|
|||||||
} ?>></td>
|
} ?>></td>
|
||||||
<td> - </td>
|
<td> - </td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Entreprise</td>
|
<td>Entreprise</td>
|
||||||
@ -615,6 +680,7 @@
|
|||||||
<td> - </td>
|
<td> - </td>
|
||||||
<td> - </td>
|
<td> - </td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Profile</td>
|
<td>Profile</td>
|
||||||
@ -628,6 +694,7 @@
|
|||||||
} ?>></td>
|
} ?>></td>
|
||||||
<td> - </td>
|
<td> - </td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
@ -642,6 +709,7 @@
|
|||||||
} ?>></td>
|
} ?>></td>
|
||||||
<td> - </td>
|
<td> - </td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
@ -657,6 +725,7 @@
|
|||||||
<td> - </td>
|
<td> - </td>
|
||||||
<td> - </td>
|
<td> - </td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@ -73,8 +73,9 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
<th>Produit</th>
|
<th>Produit</th>
|
||||||
<th>SKU</th>
|
<th>N° de série</th>
|
||||||
<th>Magasin</th>
|
<th>Magasin</th>
|
||||||
|
<th>Utilisateur</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -238,13 +239,14 @@ $(document).ready(function() {
|
|||||||
"complete": function() { $("#loading").hide(); }
|
"complete": function() { $("#loading").hide(); }
|
||||||
},
|
},
|
||||||
"columns": [
|
"columns": [
|
||||||
{ "data": 0, "width": "15%" },
|
{ "data": 0, "width": "13%" },
|
||||||
{ "data": 1, "width": "20%" },
|
{ "data": 1, "width": "15%" },
|
||||||
{ "data": 2, "width": "10%" },
|
{ "data": 2, "width": "10%" },
|
||||||
{ "data": 3, "width": "12%" },
|
{ "data": 3, "width": "12%" },
|
||||||
{
|
{ "data": 4, "width": "10%" },
|
||||||
"data": 4,
|
{
|
||||||
"width": "10%",
|
"data": 5,
|
||||||
|
"width": "8%",
|
||||||
"render": function(data) {
|
"render": function(data) {
|
||||||
let badgeClass = "badge bg-gray";
|
let badgeClass = "badge bg-gray";
|
||||||
if (data === "CREATE") badgeClass = "badge bg-green";
|
if (data === "CREATE") badgeClass = "badge bg-green";
|
||||||
@ -254,7 +256,7 @@ $(document).ready(function() {
|
|||||||
return '<span class="'+badgeClass+'">'+data+'</span>';
|
return '<span class="'+badgeClass+'">'+data+'</span>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ "data": 5, "width": "33%" }
|
{ "data": 6, "width": "32%" }
|
||||||
],
|
],
|
||||||
"order": [[0, "desc"]],
|
"order": [[0, "desc"]],
|
||||||
"pageLength": 25,
|
"pageLength": 25,
|
||||||
|
|||||||
@ -52,14 +52,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- /.box-header -->
|
<!-- /.box-header -->
|
||||||
<form role="form" action="<?php base_url('orders/create') ?>" method="post" class="form-horizontal">
|
<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">
|
<div class="box-body">
|
||||||
|
|
||||||
|
|
||||||
@ -108,6 +100,31 @@
|
|||||||
placeholder="Entrer ne CIN du client" autocomplete="off" required value="<?= old('customer_cin') ?>">
|
placeholder="Entrer ne CIN du client" autocomplete="off" required value="<?= old('customer_cin') ?>">
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -256,7 +273,30 @@
|
|||||||
'<i class="glyphicon glyphicon-tag"></i>' +
|
'<i class="glyphicon glyphicon-tag"></i>' +
|
||||||
'</button>';
|
'</button>';
|
||||||
|
|
||||||
// Add new row in the table
|
// 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 () {
|
$("#add_row").unbind('click').bind('click', function () {
|
||||||
var table = $("#product_info_table");
|
var table = $("#product_info_table");
|
||||||
var count_table_tbody_tr = $("#product_info_table tbody tr").length;
|
var count_table_tbody_tr = $("#product_info_table tbody tr").length;
|
||||||
@ -268,7 +308,6 @@
|
|||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
|
|
||||||
// console.log(reponse.x);
|
|
||||||
var html = '<tr id="row_' + row_id + '">' +
|
var html = '<tr id="row_' + row_id + '">' +
|
||||||
'<td>' +
|
'<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 + ')">' +
|
'<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 + ')">' +
|
||||||
@ -296,6 +335,9 @@
|
|||||||
|
|
||||||
$(".product").select2();
|
$(".product").select2();
|
||||||
|
|
||||||
|
// Cacher le bouton "+" si particulier et déjà 2 lignes
|
||||||
|
toggleAddRowButton();
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -413,6 +455,7 @@
|
|||||||
function removeRow(tr_id) {
|
function removeRow(tr_id) {
|
||||||
$("#product_info_table tbody tr#row_" + tr_id).remove();
|
$("#product_info_table tbody tr#row_" + tr_id).remove();
|
||||||
subAmount();
|
subAmount();
|
||||||
|
toggleAddRowButton();
|
||||||
}
|
}
|
||||||
function formatAllNumbers() {
|
function formatAllNumbers() {
|
||||||
// Sélecteur pour tous les inputs que tu veux formater
|
// Sélecteur pour tous les inputs que tu veux formater
|
||||||
|
|||||||
@ -342,9 +342,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$users = session()->get('user');
|
$users = session()->get('user');
|
||||||
if ($users && $users['group_name'] === 'Caissière'):
|
if ($users && $users['group_name'] !== 'COMMERCIALE'):
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="form-group">
|
<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">
|
<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>
|
<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">Enregistrer</button>
|
<button type="submit" class="btn btn-primary">Payer</button>
|
||||||
<a href="<?php echo base_url('orders/') ?>" class="btn btn-warning">Retour</a>
|
<a href="<?php echo base_url('orders/') ?>" class="btn btn-warning">Retour</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -43,7 +43,7 @@
|
|||||||
<h3 class="box-title">Mise à jours Moto</h3>
|
<h3 class="box-title">Mise à jours Moto</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form role="form" action="<?php base_url('users/update') ?>" method="post" enctype="multipart/form-data">
|
<form role="form" action="<?php echo base_url('products/update/' . $product_data['id']); ?>" method="post" enctype="multipart/form-data">
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
<!-- Image actuelle -->
|
<!-- Image actuelle -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -111,7 +111,7 @@
|
|||||||
<!-- Date d'arrivage -->
|
<!-- Date d'arrivage -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="datea">Date d'arrivage</label>
|
<label for="datea">Date d'arrivage</label>
|
||||||
<input type="date" class="form-control" id="datea" name="datea" autocomplete="off" value="<?php echo $product_data['date_arivage']; ?>" />
|
<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'])) : ''; ?>" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Puissance -->
|
<!-- Puissance -->
|
||||||
@ -143,19 +143,23 @@
|
|||||||
<label for="categorie">Catégories</label>
|
<label for="categorie">Catégories</label>
|
||||||
<?php
|
<?php
|
||||||
$rawCats = $product_data['categorie_id'] ?? null;
|
$rawCats = $product_data['categorie_id'] ?? null;
|
||||||
|
$catIds = [];
|
||||||
if (is_array($rawCats)) {
|
if (is_array($rawCats)) {
|
||||||
$catIds = array_map('intval', $rawCats);
|
$catIds = array_map('intval', $rawCats);
|
||||||
} elseif (is_string($rawCats)) {
|
} elseif (is_string($rawCats)) {
|
||||||
$catIds = array_filter(array_map('intval', explode(',', $rawCats)), fn($id) => $id > 0);
|
$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)) {
|
} elseif (is_int($rawCats) || ctype_digit((string)$rawCats)) {
|
||||||
$catIds = [(int) $rawCats];
|
$catIds = [(int) $rawCats];
|
||||||
} else {
|
|
||||||
$catIds = [];
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<select class="form-control select_group" id="categorie" name="categorie[]" multiple="multiple">
|
<select class="form-control select_group" id="categorie" name="categorie[]" multiple="multiple">
|
||||||
<?php foreach ($categorie as $k => $v): ?>
|
<?php foreach ($categorie as $k => $v): ?>
|
||||||
<option value="<?= $v['id']; ?>" <?= in_array($v['id'], $catIds, true) ? 'selected="selected"' : '' ?>><?= esc($v['name']); ?></option>
|
<option value="<?= $v['id']; ?>" <?= in_array((int)$v['id'], $catIds) ? 'selected="selected"' : '' ?>><?= esc($v['name']); ?></option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -155,7 +155,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Image</th>
|
<th>Image</th>
|
||||||
<th>UGS</th>
|
<th>N° SERIE </th>
|
||||||
<th>Nom de produit</th>
|
<th>Nom de produit</th>
|
||||||
<th>Prix</th>
|
<th>Prix</th>
|
||||||
<th>Magasin</th>
|
<th>Magasin</th>
|
||||||
@ -340,7 +340,12 @@
|
|||||||
'columnDefs': [{
|
'columnDefs': [{
|
||||||
targets: 3,
|
targets: 3,
|
||||||
className: 'text-right'
|
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
|
// CORRECTION: Utilisation de la délégation d'événements pour les boutons
|
||||||
|
|||||||
@ -67,7 +67,9 @@
|
|||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<?php if (in_array('updateRecouvrement', $user_permission) || in_array('deleteRecouvrement', $user_permission)): ?>
|
||||||
|
<td></td>
|
||||||
|
<?php endif; ?>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -275,7 +277,7 @@
|
|||||||
// Initialisation du DataTable
|
// Initialisation du DataTable
|
||||||
manageTable = $('#manageTable').DataTable({
|
manageTable = $('#manageTable').DataTable({
|
||||||
'ajax': '<?= base_url('recouvrement/fetchRecouvrementData') ?>',
|
'ajax': '<?= base_url('recouvrement/fetchRecouvrementData') ?>',
|
||||||
'order': [],
|
'order': [[2, 'desc']],
|
||||||
'columnDefs': [{
|
'columnDefs': [{
|
||||||
targets: 1,
|
targets: 1,
|
||||||
className: 'text-right rowmontant'
|
className: 'text-right rowmontant'
|
||||||
@ -306,18 +308,36 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
// ====== CRÉATION DE RECOUVREMENT ======
|
// ====== CRÉATION DE RECOUVREMENT ======
|
||||||
$("#create_form").unbind('submit').on('submit', function() {
|
$("#create_form").unbind('submit').on('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
var form = $(this);
|
var form = $(this);
|
||||||
|
var submitBtn = form.find('button[type="submit"]');
|
||||||
|
|
||||||
// Supprimer les messages d'erreur
|
// Supprimer les messages d'erreur
|
||||||
$(".text-danger").remove();
|
$(".text-danger").remove();
|
||||||
|
|
||||||
$.ajax({
|
// Pop-up de confirmation
|
||||||
url: form.attr('action'),
|
Swal.fire({
|
||||||
type: form.attr('method'),
|
title: 'Confirmer la création',
|
||||||
data: form.serialize(),
|
text: 'Voulez-vous vraiment enregistrer ce recouvrement ?',
|
||||||
dataType: 'json',
|
icon: 'question',
|
||||||
success: function(response) {
|
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'),
|
||||||
|
data: form.serialize(),
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
if (response.success === true) {
|
if (response.success === true) {
|
||||||
// Recharger immédiatement les données
|
// Recharger immédiatement les données
|
||||||
manageTable.ajax.reload(null, false);
|
manageTable.ajax.reload(null, false);
|
||||||
@ -374,9 +394,15 @@ $("#create_form").unbind('submit').on('submit', function() {
|
|||||||
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' +
|
'<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.' +
|
'<strong>Erreur!</strong> Une erreur est survenue lors de la création.' +
|
||||||
'</div>');
|
'</div>');
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
// Réactiver le bouton
|
||||||
|
submitBtn.prop('disabled', false).text('Enregistrer');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}); // fin Swal.then
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
// ====== SUPPRESSION DE RECOUVREMENT ======
|
// ====== SUPPRESSION DE RECOUVREMENT ======
|
||||||
|
|||||||
@ -13,19 +13,59 @@
|
|||||||
<section class="content">
|
<section class="content">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12 col-xs-12">
|
<div class="col-md-12 col-xs-12">
|
||||||
<form class="form-inline" action="<?php echo base_url('reports/'); ?>" method="POST">
|
<form action="<?php echo base_url('reports/'); ?>" method="POST">
|
||||||
<div class="form-group">
|
<div class="row" style="margin-bottom: 15px;">
|
||||||
<label for="select_year">Année</label>
|
<div class="col-md-2">
|
||||||
<select class="form-control" name="select_year" id="select_year">
|
<label for="select_year">Année</label>
|
||||||
<?php foreach ($report_years as $value): ?>
|
<select class="form-control" name="select_year" id="select_year">
|
||||||
<option value="<?php echo $value; ?>" <?php echo ($value == $selected_year) ? 'selected' : ''; ?>>
|
<?php foreach ($report_years as $value): ?>
|
||||||
<?php echo $value; ?>
|
<option value="<?php echo $value; ?>" <?php echo ($value == $selected_year) ? 'selected' : ''; ?>>
|
||||||
</option>
|
<?php echo $value; ?>
|
||||||
<?php endforeach; ?>
|
</option>
|
||||||
</select>
|
<?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>
|
</div>
|
||||||
<button type="submit" class="btn btn-default">Envoyer</button>
|
|
||||||
<a href="detail/stock" class="btn btn-sm btn-success">Détails</a>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -73,27 +73,28 @@
|
|||||||
<label for="endDate" class="form-label">Date de fin</label>
|
<label for="endDate" class="form-label">Date de fin</label>
|
||||||
<input type="date" id="endDate" class="form-control">
|
<input type="date" id="endDate" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-2">
|
||||||
<label for="pvente" class="form-label">Points de ventes</label>
|
<label for="pvente" class="form-label">Points de ventes</label>
|
||||||
<select name="" id="pvente" class="form-control">
|
<select id="pvente" class="form-control">
|
||||||
<option value="TOUS">TOUS</option>
|
<option value="TOUS">TOUS</option>
|
||||||
<?php
|
<?php foreach ($stores as $value): ?>
|
||||||
foreach ($stores as $value) {
|
<option value="<?= $value['name']; ?>"><?= $value['name']; ?></option>
|
||||||
?>
|
<?php endforeach; ?>
|
||||||
<option value="<?= $value['name']; ?>"><?= $value['name']; ?>
|
|
||||||
</option>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 d-flex align-items-end">
|
<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">
|
||||||
<br>
|
<br>
|
||||||
<button id="filteredB1" class="btn btn-primary w-100">Filtrer
|
<button id="filteredB1" class="btn btn-primary w-100">Filtrer</button>
|
||||||
🔍</button>
|
<button id="ExportBTN1" class="btn btn-success w-100">Exporter</button>
|
||||||
<button id="ExportBTN1" class="btn btn-success w-100">Exporter
|
|
||||||
📤</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table id="commperformance" class="table table-hover table-striped">
|
<table id="commperformance" class="table table-hover table-striped">
|
||||||
@ -102,7 +103,7 @@
|
|||||||
<th>Nom et prénom</th>
|
<th>Nom et prénom</th>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Motos vendue</th>
|
<th>Motos vendue</th>
|
||||||
<th>Date de vente</th><!-- return 2025-04-18 -->
|
<th>Date de vente</th>
|
||||||
<th>Prix d'achat</th>
|
<th>Prix d'achat</th>
|
||||||
<th>Prix de vente</th>
|
<th>Prix de vente</th>
|
||||||
<th>Point de ventes</th>
|
<th>Point de ventes</th>
|
||||||
@ -112,9 +113,9 @@
|
|||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="5" style="text-align:right">Total:</th>
|
<th colspan="5" style="text-align:right">Total:</th>
|
||||||
<th></th> <!-- total Prix de vente -->
|
|
||||||
<th></th>
|
<th></th>
|
||||||
<th></th> <!-- total Bénéfices -->
|
<th></th>
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
@ -135,48 +136,48 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row g-3 align-items-center mb-4" style="margin: 5px 0 5px 5px;">
|
<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-2">
|
||||||
<label for="startDate2" class="form-label">Date de début</label>
|
<label for="startDate2" class="form-label">Date de début</label>
|
||||||
<input type="date" id="startDate" class="form-control">
|
<input type="date" id="startDate2" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-2">
|
||||||
<label for="endDate2" class="form-label">Date de fin</label>
|
<label for="endDate2" class="form-label">Date de fin</label>
|
||||||
<input type="date" id="endDate" class="form-control">
|
<input type="date" id="endDate2" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-2">
|
||||||
<label for="pvente" class="form-label">Points de ventes</label>
|
<label for="pvente2" class="form-label">Points de ventes</label>
|
||||||
<select name="" id="pvente2" class="form-control">
|
<select id="pvente2" class="form-control">
|
||||||
<option value="TOUS">TOUS</option>
|
<option value="TOUS">TOUS</option>
|
||||||
<?php
|
<?php foreach ($stores as $value): ?>
|
||||||
foreach ($stores as $value) {
|
<option value="<?= $value['name']; ?>"><?= $value['name']; ?></option>
|
||||||
?>
|
<?php endforeach; ?>
|
||||||
<option value="<?= $value['name']; ?>"><?= $value['name']; ?>
|
|
||||||
</option>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 d-flex align-items-end">
|
<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">
|
||||||
<br>
|
<br>
|
||||||
<button id="filteredB2" class="btn btn-primary w-100">Filtrer
|
<button id="filteredB2" class="btn btn-primary w-100">Filtrer</button>
|
||||||
🔍</button>
|
<button id="ExportBTN2" class="btn btn-success w-100">Exporter</button>
|
||||||
<button id="ExportBTN2" class="btn btn-success w-100">Exporter
|
|
||||||
📤</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table id="mecperformance" class="table table-hover table-striped">
|
<table id="mecperformance" class="table table-hover table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Nom et prénom</th>
|
<th>Mécanicien</th>
|
||||||
<th>Email</th>
|
<th>Image</th>
|
||||||
<th>Motos vendue</th>
|
<th>Moto réparée</th>
|
||||||
<th>Date de vente</th><!-- return 2025-04-18 -->
|
<th>N° Série</th>
|
||||||
<th>Prix d'achat</th>
|
<th>Point de vente</th>
|
||||||
<th>Prix de vente</th>
|
<th>Date début</th>
|
||||||
<th>Point de ventes</th>
|
<th>Date fin</th>
|
||||||
<th>Bénefices</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
@ -200,8 +201,10 @@
|
|||||||
|
|
||||||
// Initialize the datatable
|
// Initialize the datatable
|
||||||
|
|
||||||
|
var baseUrl = '<?= base_url() ?>';
|
||||||
|
|
||||||
manageTable = $('#commperformance').DataTable({
|
manageTable = $('#commperformance').DataTable({
|
||||||
'ajax': 'fetchPerformances',
|
'ajax': baseUrl + 'reports/detail/fetchPerformances',
|
||||||
'order': [],
|
'order': [],
|
||||||
'pageLength': 5,
|
'pageLength': 5,
|
||||||
'lengthMenu': [
|
'lengthMenu': [
|
||||||
@ -241,49 +244,44 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Filtre commercial - côté serveur
|
||||||
$('#filteredB1').on('click', function () {
|
$('#filteredB1').on('click', function () {
|
||||||
const startDate = $('#startDate').val();
|
var startDate = $('#startDate').val();
|
||||||
const endDate = $('#endDate').val();
|
var endDate = $('#endDate').val();
|
||||||
const pvente = $('#pvente').val();
|
var pvente = $('#pvente').val();
|
||||||
|
var commercial = $('#commercialFilter').val();
|
||||||
|
|
||||||
// Get all original data (you may need to fetch from server or already loaded)
|
var url = baseUrl + 'reports/detail/fetchPerformances?startDate=' + startDate + '&endDate=' + endDate + '&pvente=' + pvente + '&commercial=' + commercial;
|
||||||
manageTable.ajax.url('fetchPerformances').load(function () {
|
manageTable.ajax.url(url).load();
|
||||||
const filteredData = [];
|
});
|
||||||
|
|
||||||
manageTable.rows().every(function () {
|
// DataTable mécanicien
|
||||||
const data = this.data();
|
var mecTable = $('#mecperformance').DataTable({
|
||||||
const saleDate = data[3].split(' ')[0]; // extract YYYY-MM-DD from date
|
'ajax': baseUrl + 'mecanicien/fetchMecanicienPerformances',
|
||||||
const store = data[6];
|
'order': [],
|
||||||
|
'pageLength': 10
|
||||||
|
});
|
||||||
|
|
||||||
// Filter logic
|
// Filtre mécanicien - côté serveur
|
||||||
const dateMatch = (!startDate && !endDate) ||
|
$('#filteredB2').on('click', function () {
|
||||||
(startDate && endDate && saleDate >= startDate && saleDate <= endDate) ||
|
var startDate = $('#startDate2').val();
|
||||||
(startDate && !endDate && saleDate >= startDate) ||
|
var endDate = $('#endDate2').val();
|
||||||
(!startDate && endDate && saleDate <= endDate);
|
var mecanic = $('#mecanicienFilter').val();
|
||||||
|
|
||||||
const storeMatch = (pvente === 'TOUS' || pvente === store);
|
var url = baseUrl + 'mecanicien/fetchMecanicienPerformances?startDate=' + startDate + '&endDate=' + endDate + '&mecanic_id=' + (mecanic === 'TOUS' ? '' : mecanic);
|
||||||
|
mecTable.ajax.url(url).load();
|
||||||
if (dateMatch && storeMatch) {
|
|
||||||
filteredData.push(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clear and reload table with filtered data
|
|
||||||
manageTable.clear().rows.add(filteredData).draw();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Export commercial
|
||||||
document.getElementById('ExportBTN1').addEventListener('click', function () {
|
document.getElementById('ExportBTN1').addEventListener('click', function () {
|
||||||
// Select your table
|
var wb = XLSX.utils.table_to_book(document.getElementById('commperformance'), { sheet: "Commercial" });
|
||||||
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');
|
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>
|
</script>
|
||||||
@ -57,9 +57,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<!-- Filter Bar -->
|
<!-- Filter Bar -->
|
||||||
<div class="row g-3">
|
<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="col-md-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">
|
<select id="storeFilter" class="form-control">
|
||||||
<option value="TOUS">TOUS</option>
|
<option value="TOUS">TOUS</option>
|
||||||
<?php foreach ($stores as $value) { ?>
|
<?php foreach ($stores as $value) { ?>
|
||||||
@ -67,9 +75,9 @@
|
|||||||
<?php } ?>
|
<?php } ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 d-flex align-items-end">
|
<div class="col-md-2 d-flex align-items-end">
|
||||||
<br>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -128,20 +136,27 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row g-3 align-items-center mb-4" style="margin: 5px 0 5px 5px;">
|
<div class="row g-3 align-items-center mb-4" style="margin: 5px 0 5px 5px;">
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="startDate" class="form-label">Date de début</label>
|
<label for="startDate" class="form-label">Date de début</label>
|
||||||
<input type="date" id="startDate" class="form-control">
|
<input type="date" id="startDate" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="endDate" class="form-label">Date de fin</label>
|
<label for="endDate" class="form-label">Date de fin</label>
|
||||||
<input type="date" id="endDate" class="form-control">
|
<input type="date" id="endDate" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 d-flex align-items-end">
|
<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">
|
||||||
<br>
|
<br>
|
||||||
<button id="filteredB1" class="btn btn-primary w-100">Filtrer
|
<button id="filteredB1" class="btn btn-primary w-100">Filtrer</button>
|
||||||
🔍</button>
|
<button id="ExportBTN1" class="btn btn-success w-100">Exporter</button>
|
||||||
<button id="ExportBTN1" class="btn btn-success w-100">Exporter
|
|
||||||
📤</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -188,7 +203,7 @@
|
|||||||
|
|
||||||
|
|
||||||
manageTable = $('#venteTable').DataTable({
|
manageTable = $('#venteTable').DataTable({
|
||||||
'ajax': 'fetctData/' + 0,
|
'ajax': 'fetchData/' + 0,
|
||||||
'order': [],
|
'order': [],
|
||||||
'pageLength': 5, // Set default rows per page
|
'pageLength': 5, // Set default rows per page
|
||||||
'lengthMenu': [
|
'lengthMenu': [
|
||||||
@ -198,7 +213,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
manageTable2 = $('#stockTable').DataTable({
|
manageTable2 = $('#stockTable').DataTable({
|
||||||
'ajax': 'fetctDataStock/' + 0,
|
'ajax': 'fetchDataStock/' + 0,
|
||||||
'order': [],
|
'order': [],
|
||||||
'pageLength': 5, // Set default rows per page
|
'pageLength': 5, // Set default rows per page
|
||||||
'lengthMenu': [
|
'lengthMenu': [
|
||||||
@ -209,7 +224,7 @@
|
|||||||
|
|
||||||
manageTable3 = $('#export1').DataTable({
|
manageTable3 = $('#export1').DataTable({
|
||||||
ajax: {
|
ajax: {
|
||||||
url: 'fetctDataStock2/' + 0,
|
url: 'fetchDataStock2/' + 0,
|
||||||
dataSrc: 'data'
|
dataSrc: 'data'
|
||||||
},
|
},
|
||||||
order: [],
|
order: [],
|
||||||
@ -220,14 +235,16 @@
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
const filterBtn = document.getElementById('storeFilter');
|
const storeSelect = document.getElementById('storeFilter');
|
||||||
|
|
||||||
filterBtn.addEventListener('change', function () {
|
storeSelect.addEventListener('change', function () {
|
||||||
let filterValue = filterBtn.value === "TOUS" ? "0" : filterBtn.value;
|
let filterValue = storeSelect.value === "TOUS" ? "0" : storeSelect.value;
|
||||||
|
let startDate = $('#startDateStock').val();
|
||||||
|
let endDate = $('#endDateStock').val();
|
||||||
|
let params = '?startDate=' + startDate + '&endDate=' + endDate;
|
||||||
|
|
||||||
// Update the DataTable dynamically without reinitialization
|
manageTable.ajax.url('fetchData/' + filterValue + params).load();
|
||||||
manageTable.ajax.url('fetctData/' + filterValue).load();
|
manageTable2.ajax.url('fetchDataStock/' + filterValue + params).load();
|
||||||
manageTable2.ajax.url('fetctDataStock/' + filterValue).load();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let productsSold = <?= $ventes ?>;
|
let productsSold = <?= $ventes ?>;
|
||||||
@ -249,6 +266,14 @@
|
|||||||
// Trigger the filter on button click
|
// Trigger the filter on button click
|
||||||
$('#filterBtn').click(function () {
|
$('#filterBtn').click(function () {
|
||||||
let storeId = $('#storeFilter').val();
|
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);
|
applyFilter(storeId);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -256,32 +281,14 @@
|
|||||||
applyFilter("TOUS");
|
applyFilter("TOUS");
|
||||||
});
|
});
|
||||||
|
|
||||||
$.fn.dataTable.ext.search.push(function (settings, data, dataIndex) {
|
|
||||||
if (settings.nTable.id !== 'export1') return true; // Apply only to your table
|
|
||||||
|
|
||||||
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 () {
|
$('#filteredB1').on('click', function () {
|
||||||
manageTable3.draw(); // re-filter table
|
let storeId = $('#exportStoreFilter').val();
|
||||||
|
let filterValue = storeId === "TOUS" ? "0" : storeId;
|
||||||
|
let startDate = $('#startDate').val();
|
||||||
|
let endDate = $('#endDate').val();
|
||||||
|
let params = '?startDate=' + startDate + '&endDate=' + endDate;
|
||||||
|
|
||||||
|
manageTable3.ajax.url('fetchDataStock2/' + filterValue + params).load();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -186,6 +186,33 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 -->
|
<!-- Filtres -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
@ -245,7 +272,7 @@
|
|||||||
<th>Image</th>
|
<th>Image</th>
|
||||||
<th>N° Facture</th>
|
<th>N° Facture</th>
|
||||||
<th>Désignation</th>
|
<th>Désignation</th>
|
||||||
<th>UGS</th>
|
<th>N° SERIE </th>
|
||||||
<th>Marque</th>
|
<th>Marque</th>
|
||||||
<th>Client</th>
|
<th>Client</th>
|
||||||
<th>Magasin</th>
|
<th>Magasin</th>
|
||||||
@ -266,6 +293,38 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</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 -->
|
<!-- Modal Détails -->
|
||||||
<div class="modal fade" id="detailsModal" tabindex="-1">
|
<div class="modal fade" id="detailsModal" tabindex="-1">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
@ -294,8 +353,8 @@
|
|||||||
<div class="col-xs-6"><span id="detailDesignation"></span></div>
|
<div class="col-xs-6"><span id="detailDesignation"></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" style="margin-bottom: 15px;">
|
<div class="row" style="margin-bottom: 15px;">
|
||||||
<div class="col-xs-6"><strong>UGS:</strong></div>
|
<div class="col-xs-6"><strong>N° SERIE:</strong></div>
|
||||||
<div class="col-xs-6"><span id="detailUGS"></span></div>
|
<div class="col-xs-6"><span id="detailNumSerie"></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" style="margin-bottom: 15px;">
|
<div class="row" style="margin-bottom: 15px;">
|
||||||
<div class="col-xs-6"><strong>Marque:</strong></div>
|
<div class="col-xs-6"><strong>Marque:</strong></div>
|
||||||
@ -361,7 +420,95 @@
|
|||||||
<script>
|
<script>
|
||||||
$(function() {
|
$(function() {
|
||||||
$("#securiteNav").addClass('active');
|
$("#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
|
// Configuration DataTable en français
|
||||||
$.extend(true, $.fn.dataTable.defaults, {
|
$.extend(true, $.fn.dataTable.defaults, {
|
||||||
language: {
|
language: {
|
||||||
@ -620,7 +767,7 @@ $(function() {
|
|||||||
data.push([
|
data.push([
|
||||||
'N° Facture',
|
'N° Facture',
|
||||||
'Désignation',
|
'Désignation',
|
||||||
'UGS',
|
'N° SERIE',
|
||||||
'Marque',
|
'Marque',
|
||||||
'Client',
|
'Client',
|
||||||
'Magasin',
|
'Magasin',
|
||||||
@ -671,7 +818,7 @@ function viewDetails(id) {
|
|||||||
$('#detailImage').attr('src', data[0]);
|
$('#detailImage').attr('src', data[0]);
|
||||||
$('#detailBillNo').text(data[1]);
|
$('#detailBillNo').text(data[1]);
|
||||||
$('#detailDesignation').text(data[2]);
|
$('#detailDesignation').text(data[2]);
|
||||||
$('#detailUGS').text(data[3]);
|
$('#detailNumSerie').text(data[3]);
|
||||||
$('#detailMarque').text(data[4]);
|
$('#detailMarque').text(data[4]);
|
||||||
$('#detailSerie').text(data[3]);
|
$('#detailSerie').text(data[3]);
|
||||||
$('#detailStore').text(data[7]);
|
$('#detailStore').text(data[7]);
|
||||||
|
|||||||
@ -17,26 +17,87 @@ function toggleSidebar() {
|
|||||||
document.body.classList.toggle('sidebar-collapsed');
|
document.body.classList.toggle('sidebar-collapsed');
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
$(document).ready(function() {
|
||||||
const treeviews = document.querySelectorAll('.sidebar-menu .treeview');
|
// Supprimer TOUS les handlers AdminLTE sur le menu
|
||||||
|
$('.sidebar-menu').off();
|
||||||
|
$(document).off('click', '.sidebar-menu li a');
|
||||||
|
$(document).off('click', '.treeview > a');
|
||||||
|
|
||||||
treeviews.forEach(item => {
|
// Aussi tenter de détruire le widget tree AdminLTE
|
||||||
// Quand la souris entre dans un menu
|
try { $('.sidebar-menu').tree('destroy'); } catch(e) {}
|
||||||
item.addEventListener('mouseenter', function () {
|
|
||||||
if (document.body.classList.contains('sidebar-collapsed')) {
|
|
||||||
this.classList.add('menu-open');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Quand la souris sort du menu
|
// Re-supprimer après un court délai (AdminLTE peut rebind)
|
||||||
item.addEventListener('mouseleave', function () {
|
setTimeout(function() {
|
||||||
if (document.body.classList.contains('sidebar-collapsed')) {
|
$('.sidebar-menu').off();
|
||||||
this.classList.remove('menu-open');
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('.main-sidebar').on('mouseenter', function() {
|
||||||
|
if (closeTimer) {
|
||||||
|
clearTimeout(closeTimer);
|
||||||
|
closeTimer = null;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,13 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<title><?php echo $page_title; ?></title>
|
<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 -->
|
<!-- 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">
|
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||||
<!-- Bootstrap 3.3.7 -->
|
<!-- Bootstrap 3.3.7 -->
|
||||||
@ -118,7 +125,7 @@
|
|||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="hold-transition skin-blue sidebar-mini">
|
<body class="hold-transition skin-blue sidebar-mini sidebar-collapsed">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<style>
|
<style>
|
||||||
/* ============================================
|
/* ============================================
|
||||||
@ -127,6 +134,26 @@
|
|||||||
/* ============================================
|
/* ============================================
|
||||||
VARIABLES CSS - Design System Couleurs Unies
|
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 {
|
:root {
|
||||||
--primary-color: #3498db;
|
--primary-color: #3498db;
|
||||||
--success-color: #2ecc71;
|
--success-color: #2ecc71;
|
||||||
@ -146,13 +173,12 @@ body {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-family: 'Inter', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Source Sans Pro', sans-serif !important;
|
font-family: 'Inter', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Source Sans Pro', sans-serif !important;
|
||||||
overflow-x: hidden;
|
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #3498db !important;
|
background: #3498db !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
margin-top:30px;
|
margin-top:50px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
@ -165,14 +191,14 @@ body {
|
|||||||
.content-wrapper {
|
.content-wrapper {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding-bottom: 60px;
|
overflow-x: auto;
|
||||||
margin-left: 230px;
|
margin-left: 230px;
|
||||||
padding-top: 50px;
|
width: calc(100% - 230px);
|
||||||
transition: margin-left 0.3s ease;
|
transition: margin-left 0.3s ease, width 0.3s ease;
|
||||||
background: #ecf0f1 !important;
|
background: #ecf0f1 !important;
|
||||||
box-shadow: -5px 0 20px rgba(0, 0, 0, 0.1);
|
box-shadow: -5px 0 20px rgba(0, 0, 0, 0.1);
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
padding: 30px !important;
|
padding: 75px 30px 80px 30px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
@ -188,6 +214,8 @@ body {
|
|||||||
height: 50px;
|
height: 50px;
|
||||||
transition: margin-left 0.3s ease;
|
transition: margin-left 0.3s ease;
|
||||||
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.2);
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-header {
|
.content-header {
|
||||||
@ -240,21 +268,31 @@ body {
|
|||||||
============================================ */
|
============================================ */
|
||||||
.main-sidebar {
|
.main-sidebar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 50px;
|
||||||
left: 0;
|
left: 0;
|
||||||
height: 100vh;
|
height: calc(100vh - 50px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
z-index: 810;
|
z-index: 810;
|
||||||
width: 230px;
|
width: 230px;
|
||||||
background: #2c3e50 !important;
|
background: #2c3e50 !important;
|
||||||
transition: width 0.3s ease;
|
transition: width 0.3s ease;
|
||||||
box-shadow: 2px 0 20px rgba(0, 0, 0, 0.3);
|
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 */
|
||||||
.logo {
|
.logo {
|
||||||
display: block;
|
flex-shrink: 0;
|
||||||
padding: 15px;
|
width: 230px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 15px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: #3498db !important;
|
background: #3498db !important;
|
||||||
color: white;
|
color: white;
|
||||||
@ -262,8 +300,11 @@ body {
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
transition: padding 0.3s ease;
|
transition: width 0.3s ease, padding 0.3s ease;
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
}
|
||||||
|
|
||||||
|
.main-header .navbar {
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo-mini {
|
.logo-mini {
|
||||||
@ -696,7 +737,7 @@ body {
|
|||||||
left: 230px;
|
left: 230px;
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 1000;
|
z-index: 800;
|
||||||
background: #ffffff !important;
|
background: #ffffff !important;
|
||||||
padding: 12px 20px;
|
padding: 12px 20px;
|
||||||
border-top: 2px solid #3498db;
|
border-top: 2px solid #3498db;
|
||||||
@ -713,20 +754,30 @@ body {
|
|||||||
============================================ */
|
============================================ */
|
||||||
.sidebar-toggle {
|
.sidebar-toggle {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
left: 230px;
|
left: 230px;
|
||||||
|
height: 50px;
|
||||||
|
line-height: 30px;
|
||||||
z-index: 2000;
|
z-index: 2000;
|
||||||
background: #3c8dbc;
|
background: transparent;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 8px 12px;
|
padding: 0 15px;
|
||||||
border-radius: 3px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: left 0.3s ease;
|
transition: left 0.3s ease;
|
||||||
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-collapsed .sidebar-toggle {
|
.sidebar-collapsed .sidebar-toggle {
|
||||||
left: 70px;
|
left: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-toggle::before {
|
||||||
|
content: "\f0c9";
|
||||||
|
font-family: FontAwesome;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
NOTIFICATIONS - Badge modernisé
|
NOTIFICATIONS - Badge modernisé
|
||||||
============================================ */
|
============================================ */
|
||||||
@ -791,16 +842,69 @@ body {
|
|||||||
.sidebar-collapsed .main-sidebar {
|
.sidebar-collapsed .main-sidebar {
|
||||||
width: 70px;
|
width: 70px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: visible;
|
overflow-x: hidden;
|
||||||
direction: rtl;
|
direction: rtl;
|
||||||
|
transition: width 0.35s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ouvrir la sidebar au survol */
|
||||||
|
.sidebar-collapsed .main-sidebar:hover {
|
||||||
|
width: 230px;
|
||||||
|
overflow-x: visible;
|
||||||
|
}
|
||||||
|
.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 {
|
.sidebar-collapsed .main-sidebar .sidebar-menu {
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-collapsed .content-wrapper {
|
.sidebar-collapsed .content-wrapper {
|
||||||
margin-left: 70px;
|
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 {
|
.sidebar-collapsed .main-header {
|
||||||
@ -813,11 +917,35 @@ body {
|
|||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-collapsed .main-sidebar:hover ~ .main-footer {
|
||||||
|
left: 230px;
|
||||||
|
transition: left 0.35s ease;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-collapsed .sidebar-toggle {
|
.sidebar-collapsed .sidebar-toggle {
|
||||||
left: 70px;
|
left: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-collapsed .logo {
|
.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 {
|
||||||
padding: 15px 5px;
|
padding: 15px 5px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -827,22 +955,37 @@ body {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-collapsed .logo-mini {
|
.sidebar-collapsed .main-sidebar .logo-mini {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
opacity: 1;
|
||||||
|
max-width: 60px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: opacity 0.25s ease 0.1s, max-width 0.35s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-collapsed .logo-lg {
|
.sidebar-collapsed .main-sidebar .logo-lg {
|
||||||
display: none;
|
opacity: 0;
|
||||||
|
max-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: opacity 0.25s ease, max-width 0.35s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-collapsed .sidebar-menu > li > a > span {
|
.sidebar-collapsed .sidebar-menu > li > a > span {
|
||||||
display: none;
|
opacity: 0;
|
||||||
|
max-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: opacity 0.2s ease, max-width 0.35s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-collapsed .sidebar-menu > li > a .pull-right-container {
|
.sidebar-collapsed .sidebar-menu > li > a .pull-right-container {
|
||||||
display: none;
|
opacity: 0;
|
||||||
|
max-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: opacity 0.2s ease, max-width 0.35s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-collapsed .sidebar-menu > li > a {
|
.sidebar-collapsed .sidebar-menu > li > a {
|
||||||
@ -854,7 +997,17 @@ body {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 70px;
|
width: 70px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 5px auto;
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-collapsed .sidebar-menu > li {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-collapsed .sidebar-menu > li.treeview > .treeview-menu {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-collapsed .sidebar-menu i {
|
.sidebar-collapsed .sidebar-menu i {
|
||||||
@ -865,114 +1018,31 @@ body {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pas de tooltip en mode réduit */
|
||||||
.sidebar-collapsed .sidebar-menu > li > a::before {
|
.sidebar-collapsed .sidebar-menu > li > a::before {
|
||||||
content: attr(data-tooltip);
|
display: none;
|
||||||
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-collapsed .sidebar-menu > li:hover > a::before {
|
/* Sidebar hover ouverte : sous-menus par clic (jQuery gère display) */
|
||||||
opacity: 1;
|
.sidebar-collapsed .main-sidebar:hover .treeview-menu {
|
||||||
visibility: visible;
|
position: static !important;
|
||||||
left: 80px;
|
width: auto !important;
|
||||||
}
|
background: rgba(0,0,0,0.15) !important;
|
||||||
|
border: none !important;
|
||||||
.sidebar-collapsed .treeview-menu {
|
box-shadow: none !important;
|
||||||
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;
|
opacity: 1 !important;
|
||||||
visibility: visible !important;
|
visibility: visible !important;
|
||||||
|
transform: none !important;
|
||||||
pointer-events: auto !important;
|
pointer-events: auto !important;
|
||||||
transform: translateX(0) scale(1) !important;
|
|
||||||
}
|
}
|
||||||
|
.sidebar-collapsed .main-sidebar:hover .treeview-menu > li > a {
|
||||||
.sidebar-collapsed .treeview-menu > li > a {
|
padding: 8px 15px 8px 30px;
|
||||||
padding: 8px 12px;
|
color: #b8c7ce;
|
||||||
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;
|
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;
|
color: #fff;
|
||||||
padding-left: 15px;
|
background: rgba(255,255,255,0.1);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
@ -1167,12 +1237,7 @@ body {
|
|||||||
left: 10px;
|
left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Treeview menu sur mobile */
|
|
||||||
.sidebar-collapsed .treeview-menu {
|
|
||||||
left: 70px;
|
|
||||||
width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Charts containers */
|
/* Charts containers */
|
||||||
.col-lg-6[style*="background-color: white"] {
|
.col-lg-6[style*="background-color: white"] {
|
||||||
padding: 15px !important;
|
padding: 15px !important;
|
||||||
@ -1563,9 +1628,7 @@ body {
|
|||||||
.small-box:nth-child(4) { animation-delay: 0.4s; }
|
.small-box:nth-child(4) { animation-delay: 0.4s; }
|
||||||
.small-box:nth-child(5) { animation-delay: 0.5s; }
|
.small-box:nth-child(5) { animation-delay: 0.5s; }
|
||||||
|
|
||||||
.sidebar-collapsed .treeview:hover .treeview-menu {
|
/* animation removed - using click-based submenus */
|
||||||
animation: slideInFromSidebar 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Désactiver les animations sur mobile pour de meilleures performances */
|
/* Désactiver les animations sur mobile pour de meilleures performances */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
@ -1578,6 +1641,16 @@ body {
|
|||||||
* {
|
* {
|
||||||
transition-duration: 0.2s !important;
|
transition-duration: 0.2s !important;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-box-number {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-header {
|
||||||
|
font-size: 24px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mobiles et petites tablettes (max-width: 768px) */
|
/* Mobiles et petites tablettes (max-width: 768px) */
|
||||||
|
|||||||
@ -1,25 +1,23 @@
|
|||||||
<header class="main-header">
|
<header class="main-header">
|
||||||
<!-- Logo -->
|
<!-- Logo -->
|
||||||
<a href="#" class="logo">
|
<a href="#" class="logo">
|
||||||
<span class="logo-mini"><b><img src="<?= base_url('assets/images/company_logo.jpg') ?>"></b></span>
|
<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>MotorBike</b></span>
|
<span class="logo-lg"><b><?= $company_name ?? 'MotorBike' ?></b></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Header Navbar -->
|
<!-- Header Navbar -->
|
||||||
<nav class="navbar navbar-static-top" style="position: relative; height: 50px; background: #3c8dbc;">
|
<nav class="navbar navbar-static-top" style="position: relative; height: 50px; background: #3c8dbc;">
|
||||||
<!-- Sidebar toggle button -->
|
<!-- Sidebar toggle button -->
|
||||||
<a href="#" class="sidebar-toggle" onclick="toggleSidebar()">
|
<a href="#" class="sidebar-toggle" onclick="toggleSidebar()"></a>
|
||||||
<span class="sr-only">Toggle navigation</span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- Navbar Right Menu -->
|
<!-- 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;">
|
<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 -->
|
<!-- Notifications -->
|
||||||
<li class="nav-item dropdown" style="position: relative;">
|
<li class="nav-item" style="position: relative;">
|
||||||
<i class="fa fa-bell" id="notificationIcon" style="font-size: 20px; cursor: pointer; color:white;" data-toggle="dropdown"></i>
|
<i class="fa fa-bell" id="notificationIcon" style="font-size: 20px; cursor: pointer; color:white;" onclick="toggleNotifPanel()"></i>
|
||||||
<span id="notificationCount" class="navbar-badge"></span>
|
<span id="notificationCount" class="navbar-badge"></span>
|
||||||
<div class="dropdown-menu dropdown-menu-right notif-dropdown">
|
<div id="notifPanel" class="notif-dropdown" style="display:none; position:absolute; right:0; top:35px; z-index:9999;">
|
||||||
<div class="notif-panel-header">
|
<div class="notif-panel-header">
|
||||||
<span class="notif-panel-title" id="notificationHeader">
|
<span class="notif-panel-title" id="notificationHeader">
|
||||||
<i class="fa fa-bell"></i> Notifications
|
<i class="fa fa-bell"></i> Notifications
|
||||||
@ -78,7 +76,7 @@
|
|||||||
width: 420px;
|
width: 420px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
max-height: 520px;
|
max-height: 520px;
|
||||||
display: none;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -86,12 +84,6 @@
|
|||||||
border: 1px solid rgba(0,0,0,0.08);
|
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 */
|
/* Header du panel */
|
||||||
.notif-panel-header {
|
.notif-panel-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -132,6 +124,7 @@
|
|||||||
#notificationList {
|
#notificationList {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
max-height: 460px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
background: #f8f9fa;
|
background: #f8f9fa;
|
||||||
}
|
}
|
||||||
@ -240,6 +233,21 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<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() {
|
function fetchNotifications() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/notifications',
|
url: '/notifications',
|
||||||
@ -365,4 +373,47 @@ $(document).on('click', '#markAllAsReadBtn', function(e) {
|
|||||||
|
|
||||||
setInterval(fetchNotifications, 10000);
|
setInterval(fetchNotifications, 10000);
|
||||||
fetchNotifications();
|
fetchNotifications();
|
||||||
</script>
|
|
||||||
|
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,7 +273,6 @@
|
|||||||
<li id="reportNav">
|
<li id="reportNav">
|
||||||
<a href="<?php echo base_url('reports/') ?>">
|
<a href="<?php echo base_url('reports/') ?>">
|
||||||
<i class="glyphicon glyphicon-stats"></i> <span>Rapports</span>
|
<i class="glyphicon glyphicon-stats"></i> <span>Rapports</span>
|
||||||
<span class="tooltip">Rapports</span>
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@ -286,6 +285,18 @@
|
|||||||
</li>
|
</li>
|
||||||
<?php endif; ?> -->
|
<?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)): ?>
|
<?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>
|
<li id="companyNav"><a href="<?php echo base_url('company/') ?>"><i class="fa fa-building"></i> <span>Entreprise</span></a></li>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
@ -53,9 +53,7 @@
|
|||||||
<th>Phone</th>
|
<th>Phone</th>
|
||||||
<th>Point de vente</th>
|
<th>Point de vente</th>
|
||||||
<th>Role</th>
|
<th>Role</th>
|
||||||
<?php if (in_array('updateUser', $user_permission) || in_array('deleteUser', $user_permission)): ?>
|
<th>Action</th>
|
||||||
<th>Action</th>
|
|
||||||
<?php endif; ?>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user