feat: afficher les infos complètes du moto dans les notifications de remise
- Remise.php : ajout méthode getFullProductInfoByDemandeId() avec JOIN orders_item/products/brands - RemiseController.php : utilisation des infos complètes (modèle, marque, N° série, N° moteur, châssis, puissance) dans les notifications de validation/refus - OrderController.php : enrichissement du message de notification lors de la création d'une demande de remise - header_menu.php : refonte complète du design des notifications (cartes colorées par type, badge, horloge relative, point non-lu)
This commit is contained in:
parent
ea81d9826d
commit
3c7585b3a2
2
.vscode/sftp.json
vendored
2
.vscode/sftp.json
vendored
@ -6,7 +6,7 @@
|
|||||||
"username": "motorbike",
|
"username": "motorbike",
|
||||||
"remotePath": "/home/motorbike/public_html/",
|
"remotePath": "/home/motorbike/public_html/",
|
||||||
"password": "IVrMDogT3XiBcrY",
|
"password": "IVrMDogT3XiBcrY",
|
||||||
"uploadOnSave": false,
|
"uploadOnSave": true,
|
||||||
"useTempFile": false,
|
"useTempFile": false,
|
||||||
"openSsh": false
|
"openSsh": false
|
||||||
}
|
}
|
||||||
|
|||||||
117
README.md
Normal file
117
README.md
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
# MOTORBiKE
|
||||||
|
|
||||||
|
Application web de gestion commerciale pour une entreprise de vente et maintenance de motos, developpee avec CodeIgniter 4.
|
||||||
|
|
||||||
|
## Fonctionnalites
|
||||||
|
|
||||||
|
- **Gestion des ventes / commandes** - creation, modification, suivi et impression de bons de livraison
|
||||||
|
- **Avances** - gestion des acomptes clients avec conversion automatique en commande et alertes d'echeance
|
||||||
|
- **Recouvrement** - suivi des paiements et creances
|
||||||
|
- **Caisse / Sortie caisse** - gestion des encaissements et decaissements avec export Excel/CSV
|
||||||
|
- **Produits** - catalogue avec attributs, categories, marques, images et import depuis Excel
|
||||||
|
- **Stocks** - affectation des produits par magasin/point de vente
|
||||||
|
- **Mecaniciens** - suivi des performances des techniciens
|
||||||
|
- **Utilisateurs & Groupes** - gestion des acces par roles et groupes de permissions
|
||||||
|
- **Magasins** - gestion multi-points de vente
|
||||||
|
- **Statistiques & Rapports** - tableaux de bord, rapports de ventes, de stock et de performances
|
||||||
|
- **Historique** - traçabilite des actions avec export
|
||||||
|
- **Notifications** - alertes en temps reel (echeances, etc.)
|
||||||
|
- **QR Code** - generation de QR codes produits
|
||||||
|
- **Securite** - validation de securite avec historique
|
||||||
|
|
||||||
|
## Stack technique
|
||||||
|
|
||||||
|
- **Framework** : CodeIgniter 4 (PHP 8.2+)
|
||||||
|
- **Base de donnees** : MySQL (via MySQLi)
|
||||||
|
- **Authentification** : JWT (`firebase/php-jwt`)
|
||||||
|
- **Export** : PhpSpreadsheet (`phpoffice/phpspreadsheet`)
|
||||||
|
- **Tests** : PHPUnit 9
|
||||||
|
|
||||||
|
## Prerequis
|
||||||
|
|
||||||
|
- PHP >= 8.2 avec les extensions : `curl`, `intl`, `json`, `mbstring`, `mysqli`
|
||||||
|
- MySQL >= 5.7 / MariaDB
|
||||||
|
- Composer
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Cloner le depot
|
||||||
|
git clone <url-du-depot> motorbike
|
||||||
|
cd motorbike
|
||||||
|
|
||||||
|
# Installer les dependances
|
||||||
|
composer install
|
||||||
|
|
||||||
|
# Configurer l'environnement
|
||||||
|
cp .env.example .env
|
||||||
|
# Editer .env avec vos parametres de base de donnees et URL
|
||||||
|
|
||||||
|
# Executer les migrations
|
||||||
|
php spark migrate
|
||||||
|
|
||||||
|
# Lancer le serveur de developpement
|
||||||
|
php spark serve
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration (.env)
|
||||||
|
|
||||||
|
```ini
|
||||||
|
CI_ENVIRONMENT = development
|
||||||
|
|
||||||
|
app.baseURL = 'http://localhost:8080/'
|
||||||
|
|
||||||
|
database.default.hostname = localhost
|
||||||
|
database.default.database = motorbike
|
||||||
|
database.default.username = <votre_utilisateur>
|
||||||
|
database.default.password = <votre_mot_de_passe>
|
||||||
|
database.default.DBDriver = MySQLi
|
||||||
|
database.default.port = 3306
|
||||||
|
```
|
||||||
|
|
||||||
|
## Structure du projet
|
||||||
|
|
||||||
|
```
|
||||||
|
app/
|
||||||
|
Config/ - Configuration (routes, filtres, base de donnees...)
|
||||||
|
Controllers/ - Controleurs de l'application
|
||||||
|
Database/ - Migrations et seeds
|
||||||
|
Filters/ - Filtres d'authentification (auth, loggedIn, publicCheck)
|
||||||
|
Models/ - Modeles de donnees
|
||||||
|
Views/ - Templates (dashboard, commandes, produits, rapports...)
|
||||||
|
public/
|
||||||
|
assets/ - CSS, JS, images
|
||||||
|
```
|
||||||
|
|
||||||
|
## Routes principales
|
||||||
|
|
||||||
|
| Chemin | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| `/` | Tableau de bord |
|
||||||
|
| `/login` | Authentification |
|
||||||
|
| `/orders` | Commandes / Ventes |
|
||||||
|
| `/avances` | Gestion des avances |
|
||||||
|
| `/products` | Catalogue produits |
|
||||||
|
| `/stores` | Magasins |
|
||||||
|
| `/recouvrement` | Recouvrement |
|
||||||
|
| `/sortieCaisse` | Sortie de caisse |
|
||||||
|
| `/reports` | Rapports |
|
||||||
|
| `/statistic` | Statistiques |
|
||||||
|
| `/users` | Utilisateurs |
|
||||||
|
| `/groups` | Groupes / Roles |
|
||||||
|
| `/brands` | Marques |
|
||||||
|
| `/category` | Categories |
|
||||||
|
| `/mecanicien` | Mecaniciens |
|
||||||
|
| `/historique` | Historique |
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer test
|
||||||
|
# ou
|
||||||
|
php spark test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
MIT
|
||||||
@ -20,6 +20,17 @@ use Kint\Renderer\Rich\ValuePluginInterface;
|
|||||||
*/
|
*/
|
||||||
class Kint extends BaseConfig
|
class Kint extends BaseConfig
|
||||||
{
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
// ini_get('xdebug.file_link_format') returns false when xdebug is not
|
||||||
|
// installed. Kint's init.php assigns this directly, making str_replace()
|
||||||
|
// throw a TypeError on PHP 8.2+. Reset to empty string when false.
|
||||||
|
if (\Kint\Kint::$file_link_format === false) {
|
||||||
|
\Kint\Kint::$file_link_format = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Global Settings
|
| Global Settings
|
||||||
|
|||||||
@ -218,7 +218,7 @@ class OrderController extends AdminController
|
|||||||
// ========================================
|
// ========================================
|
||||||
// POUR DIRECTION OU DAF
|
// POUR DIRECTION OU DAF
|
||||||
// ========================================
|
// ========================================
|
||||||
elseif($users['group_name'] == "Direction" || $users['group_name'] == "DAF" || $users['group_name'] == "SuperAdmin" ){
|
elseif(in_array($users['group_name'], ["Direction", "DAF", "SuperAdmin", "Administrator"])){
|
||||||
foreach ($data as $key => $value) {
|
foreach ($data as $key => $value) {
|
||||||
$date_time = date('d-m-Y h:i a', strtotime($value['date_time']));
|
$date_time = date('d-m-Y h:i a', strtotime($value['date_time']));
|
||||||
|
|
||||||
@ -594,12 +594,15 @@ class OrderController extends AdminController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$product_lines = [];
|
$product_lines = [];
|
||||||
|
$product_info_lines = [];
|
||||||
foreach ($product_data_results as $product) {
|
foreach ($product_data_results as $product) {
|
||||||
if (isset($product['sku'], $product['price'])) {
|
if (isset($product['sku'], $product['price'])) {
|
||||||
$sku = $product['sku'];
|
$product_lines[] = $product['sku'] . ':' . $product['price'];
|
||||||
$price = $product['price'];
|
|
||||||
$product_lines[] = "{$sku}:{$price}";
|
|
||||||
}
|
}
|
||||||
|
$product_info_lines[] = "• " . ($product['name'] ?? '-') .
|
||||||
|
" | N° Série : " . ($product['sku'] ?? '-') .
|
||||||
|
" | N° Moteur : " . ($product['numero_de_moteur'] ?? '-') .
|
||||||
|
" | Châssis : " . ($product['chasis'] ?? '-');
|
||||||
}
|
}
|
||||||
|
|
||||||
$product_output = implode("\n", $product_lines);
|
$product_output = implode("\n", $product_lines);
|
||||||
@ -623,7 +626,8 @@ class OrderController extends AdminController
|
|||||||
$message = "💰 Nouvelle demande de remise : {$montantFormatted} Ar<br>" .
|
$message = "💰 Nouvelle demande de remise : {$montantFormatted} Ar<br>" .
|
||||||
"Commande : {$bill_no}<br>" .
|
"Commande : {$bill_no}<br>" .
|
||||||
"Store : " . $this->returnStore($users['store_id']) . "<br>" .
|
"Store : " . $this->returnStore($users['store_id']) . "<br>" .
|
||||||
"Demandeur : {$users['firstname']} {$users['lastname']}";
|
"Demandeur : {$users['firstname']} {$users['lastname']}<br>" .
|
||||||
|
implode("<br>", $product_info_lines);
|
||||||
|
|
||||||
if (is_array($allStores) && count($allStores) > 0) {
|
if (is_array($allStores) && count($allStores) > 0) {
|
||||||
foreach ($allStores as $store) {
|
foreach ($allStores as $store) {
|
||||||
|
|||||||
@ -129,15 +129,28 @@ class RemiseController extends AdminController
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($Remise->updateRemise($id_demande, $data)) {
|
if ($Remise->updateRemise($id_demande, $data)) {
|
||||||
$remise_product = $Remise->getProductByDemandeId($id_demande);
|
|
||||||
$Notification = new NotificationController();
|
$Notification = new NotificationController();
|
||||||
$ordersModel = new Orders();
|
$ordersModel = new Orders();
|
||||||
$order_id = $Remise->getOrderIdByDemandeId($id_demande);
|
$order_id = $Remise->getOrderIdByDemandeId($id_demande);
|
||||||
|
|
||||||
// ✅ Récupérer les infos de la commande
|
// Récupérer les infos de la commande
|
||||||
$order_info = $ordersModel->getOrdersData($order_id);
|
$order_info = $ordersModel->getOrdersData($order_id);
|
||||||
$bill_no = $order_info['bill_no'] ?? '';
|
$bill_no = $order_info['bill_no'] ?? '';
|
||||||
$store_id = $order_info['store_id'] ?? 0;
|
$store_id = $order_info['store_id'] ?? 0;
|
||||||
|
|
||||||
|
// Récupérer les infos complètes des motos
|
||||||
|
$products_info = $Remise->getFullProductInfoByDemandeId($id_demande);
|
||||||
|
$remise_product = '';
|
||||||
|
foreach ($products_info as $p) {
|
||||||
|
$remise_product .= "<br>• Modèle : " . ($p['name'] ?? '-');
|
||||||
|
$remise_product .= " | Marque : " . ($p['marque_name'] ?? '-');
|
||||||
|
$remise_product .= " | N° Série : " . ($p['sku'] ?? '-');
|
||||||
|
$remise_product .= " | N° Moteur : " . ($p['numero_de_moteur'] ?? '-');
|
||||||
|
$remise_product .= " | Châssis : " . ($p['chasis'] ?? '-');
|
||||||
|
if (!empty($p['puissance'])) {
|
||||||
|
$remise_product .= " | Puissance : " . $p['puissance'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ✅ RÉCUPÉRER TOUS LES STORES
|
// ✅ RÉCUPÉRER TOUS LES STORES
|
||||||
$Stores = new Stores();
|
$Stores = new Stores();
|
||||||
|
|||||||
@ -46,7 +46,7 @@ function checkDeadlineAlerts()
|
|||||||
log_message('error', "Aucun email DAF trouvé");
|
log_message('error', "Aucun email DAF trouvé");
|
||||||
|
|
||||||
$db = \Config\Database::connect();
|
$db = \Config\Database::connect();
|
||||||
$allGroups = $db->query("SELECT DISTINCT group_name FROM groups")->getResult();
|
$allGroups = $db->query("SELECT DISTINCT group_name FROM `groups`")->getResult();
|
||||||
log_message('info', "Groupes disponibles: " . json_encode($allGroups));
|
log_message('info', "Groupes disponibles: " . json_encode($allGroups));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -131,7 +131,7 @@ class Orders extends Model
|
|||||||
$groupName = $group['group_name'] ?? '';
|
$groupName = $group['group_name'] ?? '';
|
||||||
|
|
||||||
// Selon le rôle
|
// Selon le rôle
|
||||||
if (in_array($groupName, ['Direction', 'SuperAdmin', 'DAF'], true)) {
|
if (in_array($groupName, ['Direction', 'SuperAdmin', 'DAF', 'Administrator'], true)) {
|
||||||
return $builder
|
return $builder
|
||||||
->orderBy('orders.id', 'DESC')
|
->orderBy('orders.id', 'DESC')
|
||||||
->get()
|
->get()
|
||||||
|
|||||||
@ -88,9 +88,23 @@ class Remise extends Model
|
|||||||
$row = $this->select('product')
|
$row = $this->select('product')
|
||||||
->where('id_demande', $id_demande)
|
->where('id_demande', $id_demande)
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
return $row['product'] ?? null;
|
return $row['product'] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFullProductInfoByDemandeId(int $id_demande): array
|
||||||
|
{
|
||||||
|
$order_id = $this->getOrderIdByDemandeId($id_demande);
|
||||||
|
if (!$order_id) return [];
|
||||||
|
|
||||||
|
return $this->db->table('orders_item')
|
||||||
|
->select('products.name, products.sku, products.numero_de_moteur, products.chasis, products.puissance, brands.name as marque_name')
|
||||||
|
->join('products', 'products.id = orders_item.product_id', 'left')
|
||||||
|
->join('brands', 'brands.id = products.marque', 'left')
|
||||||
|
->where('orders_item.order_id', $order_id)
|
||||||
|
->get()
|
||||||
|
->getResultArray();
|
||||||
|
}
|
||||||
|
|
||||||
public function updateRemise1(int $id, $data)
|
public function updateRemise1(int $id, $data)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -284,14 +284,13 @@
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
<div class="table-responsive">
|
|
||||||
<table id="historyTable" class="table table-bordered table-striped table-hover">
|
<table id="historyTable" class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Montant</th>
|
<th>Montant</th>
|
||||||
<th>Mode</th> <!-- ✅ NOUVELLE COLONNE -->
|
<th>Mode</th>
|
||||||
<th>Commentaire</th>
|
<th>Commentaire</th>
|
||||||
<th>Créé par</th>
|
<th>Créé par</th>
|
||||||
<th>Magasin</th>
|
<th>Magasin</th>
|
||||||
@ -303,7 +302,6 @@
|
|||||||
<!-- Les données seront chargées par DataTables -->
|
<!-- Les données seront chargées par DataTables -->
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -38,8 +38,7 @@
|
|||||||
<h3 class="box-title">Gérer les remises</h3>
|
<h3 class="box-title">Gérer les remises</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-responsive">
|
<table id="manageTable" class="table table-bordered table-striped">
|
||||||
<table id="manageTable" class="table table-bordered table-striped ">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
@ -53,7 +52,6 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -68,8 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
<div class="table-responsive">
|
<table id="historiqueTable" class="table table-bordered table-striped table-hover" style="width:100%;">
|
||||||
<table id="historiqueTable" class="table table-bordered table-striped table-hover nowrap" style="width:100%;">
|
|
||||||
<thead class="bg-light-blue">
|
<thead class="bg-light-blue">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
@ -82,8 +81,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Loader -->
|
<!-- Loader -->
|
||||||
<div id="loading" style="display:none;text-align:center;margin:20px;">
|
<div id="loading" style="display:none;text-align:center;margin:20px;">
|
||||||
<i class="fa fa-spinner fa-spin fa-2x text-blue"></i>
|
<i class="fa fa-spinner fa-spin fa-2x text-blue"></i>
|
||||||
|
|||||||
@ -46,11 +46,11 @@
|
|||||||
<table id="manageTable" class="table table-bordered table-striped">
|
<table id="manageTable" class="table table-bordered table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<?php
|
||||||
<?php
|
|
||||||
$session = session();
|
$session = session();
|
||||||
$users = $session->get('user');
|
$users = $session->get('user');
|
||||||
if ($users['group_name'] === 'SuperAdmin' || $users['group_name'] === "Direction" || $users['group_name'] === "DAF" ) {
|
$groupName = $users['group_name'];
|
||||||
|
if (in_array($groupName, ['SuperAdmin', 'Direction', 'DAF', 'Administrator'])) {
|
||||||
?>
|
?>
|
||||||
<th>Facture n°</th>
|
<th>Facture n°</th>
|
||||||
<th>Nom du client</th>
|
<th>Nom du client</th>
|
||||||
@ -59,7 +59,6 @@
|
|||||||
<th>Prix demandé</th>
|
<th>Prix demandé</th>
|
||||||
<th>Prix de vente</th>
|
<th>Prix de vente</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
|
|
||||||
<?php if (
|
<?php if (
|
||||||
in_array('updateOrder', $user_permission)
|
in_array('updateOrder', $user_permission)
|
||||||
|| in_array('viewOrder', $user_permission)
|
|| in_array('viewOrder', $user_permission)
|
||||||
@ -67,14 +66,7 @@
|
|||||||
) { ?>
|
) { ?>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<?php } ?>
|
<?php } elseif ($groupName === 'SECURITE') { ?>
|
||||||
|
|
||||||
<?php
|
|
||||||
$session = session();
|
|
||||||
$users = $session->get('user');
|
|
||||||
// Interface spécifique pour SECURITE
|
|
||||||
if ($users['group_name'] === 'SECURITE') {
|
|
||||||
?>
|
|
||||||
<th>Nom du produit</th>
|
<th>Nom du produit</th>
|
||||||
<th>Commerciale</th>
|
<th>Commerciale</th>
|
||||||
<th>Date et Heure</th>
|
<th>Date et Heure</th>
|
||||||
@ -87,9 +79,7 @@
|
|||||||
) { ?>
|
) { ?>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<?php } elseif ($users['group_name'] === 'COMMERCIALE' || $users['group_name'] === 'Caissière' || $users['group_name'] === "Cheffe d'Agence") {
|
<?php } else { // COMMERCIALE, Caissière, Cheffe d'Agence, et tous les autres rôles ?>
|
||||||
// Interface pour les autres rôles (COMMERCIALE, Caissière, Cheffe d'Agence)
|
|
||||||
?>
|
|
||||||
<th>Nom du produit</th>
|
<th>Nom du produit</th>
|
||||||
<th>Commerciale</th>
|
<th>Commerciale</th>
|
||||||
<th>Date et Heure</th>
|
<th>Date et Heure</th>
|
||||||
|
|||||||
@ -19,7 +19,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Tableau des recouvrements -->
|
<!-- Tableau des recouvrements -->
|
||||||
<div class="table-responsive">
|
|
||||||
<table id="recouvrement_table" class="table table-hover table-bordered">
|
<table id="recouvrement_table" class="table table-hover table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -32,7 +31,6 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Résumé des paiements -->
|
<!-- Résumé des paiements -->
|
||||||
<div class="row text-center mt-4">
|
<div class="row text-center mt-4">
|
||||||
|
|||||||
@ -145,7 +145,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table id="export1"
|
<table id="export1"
|
||||||
class="table table-hover table-striped table-bordered">
|
class="table table-hover table-striped table-bordered">
|
||||||
<thead class="table-primary">
|
<thead class="table-primary">
|
||||||
@ -161,7 +160,6 @@
|
|||||||
<!-- DataTables will populate this -->
|
<!-- DataTables will populate this -->
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -239,7 +239,6 @@
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
<div class="table-responsive">
|
|
||||||
<table id="historyTable" class="table table-bordered table-striped table-hover">
|
<table id="historyTable" class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -260,7 +259,6 @@
|
|||||||
<!-- Les données seront chargées par DataTables -->
|
<!-- Les données seront chargées par DataTables -->
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -33,6 +33,8 @@
|
|||||||
href="<?php echo base_url('assets/plugins/bootstrap-wysihtml5/bootstrap3-wysihtml5.min.css') ?>">
|
href="<?php echo base_url('assets/plugins/bootstrap-wysihtml5/bootstrap3-wysihtml5.min.css') ?>">
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
href="<?php echo base_url('assets/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css') ?>">
|
href="<?php echo base_url('assets/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css') ?>">
|
||||||
|
<!-- DataTables Responsive -->
|
||||||
|
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.5.0/css/responsive.bootstrap.min.css">
|
||||||
<!-- Select2 -->
|
<!-- Select2 -->
|
||||||
<link rel="stylesheet" href="<?php echo base_url('assets/bower_components/select2/dist/css/select2.min.css') ?>">
|
<link rel="stylesheet" href="<?php echo base_url('assets/bower_components/select2/dist/css/select2.min.css') ?>">
|
||||||
<link rel="stylesheet" href="<?php echo base_url('assets/plugins/fileinput/fileinput.min.css') ?>">
|
<link rel="stylesheet" href="<?php echo base_url('assets/plugins/fileinput/fileinput.min.css') ?>">
|
||||||
@ -99,8 +101,14 @@
|
|||||||
|
|
||||||
<!-- DataTables -->
|
<!-- DataTables -->
|
||||||
<script src="<?php echo base_url('assets/bower_components/datatables.net/js/jquery.dataTables.min.js') ?>"></script>
|
<script src="<?php echo base_url('assets/bower_components/datatables.net/js/jquery.dataTables.min.js') ?>"></script>
|
||||||
<script
|
<script src="<?php echo base_url('assets/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js') ?>"></script>
|
||||||
src="<?php echo base_url('assets/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js') ?>"></script>
|
<!-- DataTables Responsive -->
|
||||||
|
<script src="https://cdn.datatables.net/responsive/2.5.0/js/dataTables.responsive.min.js"></script>
|
||||||
|
<script src="https://cdn.datatables.net/responsive/2.5.0/js/responsive.bootstrap.min.js"></script>
|
||||||
|
<script>
|
||||||
|
// Enable responsive for all DataTables globally
|
||||||
|
$.extend(true, $.fn.dataTable.defaults, { responsive: true });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -18,18 +18,17 @@
|
|||||||
<!-- Notifications -->
|
<!-- Notifications -->
|
||||||
<li class="nav-item dropdown" style="position: relative;">
|
<li class="nav-item dropdown" style="position: relative;">
|
||||||
<i class="fa fa-bell" id="notificationIcon" style="font-size: 20px; cursor: pointer; color:white;" data-toggle="dropdown"></i>
|
<i class="fa fa-bell" id="notificationIcon" style="font-size: 20px; cursor: pointer; color:white;" data-toggle="dropdown"></i>
|
||||||
<span id="notificationCount" class="badge badge-warning navbar-badge"></span>
|
<span id="notificationCount" class="navbar-badge"></span>
|
||||||
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-right"
|
<div class="dropdown-menu dropdown-menu-right notif-dropdown">
|
||||||
style="width: 400px; padding: 5%; max-height: 500px; overflow: auto; margin-right: 5px;">
|
<div class="notif-panel-header">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; padding: 0 10px;">
|
<span class="notif-panel-title" id="notificationHeader">
|
||||||
<span class="dropdown-header" id="notificationHeader" style="padding: 0;">0 Notifications</span>
|
<i class="fa fa-bell"></i> Notifications
|
||||||
<button id="markAllAsReadBtn" class="btn btn-sm btn-primary" style="font-size: 12px; padding: 4px 10px;">
|
</span>
|
||||||
<i class="fa fa-check"></i> Marquer tout comme lu
|
<button id="markAllAsReadBtn" style="display:none;">
|
||||||
|
<i class="fa fa-check-double"></i> Tout lire
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown-divider"></div>
|
|
||||||
<div id="notificationList"></div>
|
<div id="notificationList"></div>
|
||||||
<div class="dropdown-divider"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@ -59,43 +58,178 @@
|
|||||||
|
|
||||||
<!-- Styles -->
|
<!-- Styles -->
|
||||||
<style>
|
<style>
|
||||||
/* Notifications non lues */
|
|
||||||
.notification_item.unread {
|
|
||||||
font-weight: bold;
|
|
||||||
background-color: #f0f8ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-unread {
|
|
||||||
color: #007bff;
|
|
||||||
}
|
|
||||||
|
|
||||||
#markAllAsReadBtn {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
#markAllAsReadBtn:hover {
|
|
||||||
background-color: #0056b3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style pour le dropdown utilisateur */
|
|
||||||
.dropdown-item {
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-item:hover {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-badge {
|
.navbar-badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -8px;
|
top: -8px;
|
||||||
right: -8px;
|
right: -8px;
|
||||||
padding: 3px 6px;
|
padding: 3px 6px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: #f39c12;
|
background: #e74c3c;
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
min-width: 18px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown container */
|
||||||
|
.notif-dropdown {
|
||||||
|
width: 420px;
|
||||||
|
padding: 0;
|
||||||
|
max-height: 520px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 8px 30px rgba(0,0,0,0.15);
|
||||||
|
border: 1px solid rgba(0,0,0,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header du panel */
|
||||||
|
.notif-panel-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 14px 16px;
|
||||||
|
background: linear-gradient(135deg, #2c3e50, #3498db);
|
||||||
|
color: white;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notif-panel-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#markAllAsReadBtn {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
border: 1px solid rgba(255,255,255,0.4);
|
||||||
|
color: white;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#markAllAsReadBtn:hover {
|
||||||
|
background: rgba(255,255,255,0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Liste scrollable */
|
||||||
|
#notificationList {
|
||||||
|
overflow-y: auto;
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
#notificationList:empty::after {
|
||||||
|
content: 'Aucune notification';
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
padding: 30px;
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carte de notification */
|
||||||
|
.notif-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
background: #fff;
|
||||||
|
text-decoration: none !important;
|
||||||
|
color: inherit !important;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
transition: box-shadow 0.2s, transform 0.1s;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notif-card:hover {
|
||||||
|
box-shadow: 0 3px 12px rgba(0,0,0,0.1);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
text-decoration: none !important;
|
||||||
|
color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notif-card.notif-unread {
|
||||||
|
background: #f0f7ff;
|
||||||
|
border-color: #b8d9f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Barre colorée à gauche */
|
||||||
|
.notif-accent {
|
||||||
|
width: 5px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Corps de la notif */
|
||||||
|
.notif-body {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px 12px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* En-tête : type + heure */
|
||||||
|
.notif-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notif-type-badge {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 20px;
|
||||||
|
color: #fff;
|
||||||
|
white-space: nowrap;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notif-time {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #999;
|
||||||
|
white-space: nowrap;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Contenu du message */
|
||||||
|
.notif-message {
|
||||||
|
font-size: 12.5px;
|
||||||
|
color: #444;
|
||||||
|
line-height: 1.55;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notif-card.notif-unread .notif-message {
|
||||||
|
color: #1a1a2e;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Point bleu "non lu" */
|
||||||
|
.notif-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #3498db;
|
||||||
|
flex-shrink: 0;
|
||||||
|
align-self: flex-start;
|
||||||
|
margin: 12px 10px 0 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@ -110,30 +244,73 @@ function fetchNotifications() {
|
|||||||
let notificationHTML = '';
|
let notificationHTML = '';
|
||||||
|
|
||||||
data.forEach(notif => {
|
data.forEach(notif => {
|
||||||
if (notif.is_read == 0) {
|
if (notif.is_read == 0) notificationCount++;
|
||||||
notificationCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const href = '/' + notif.link.replace(/^\/+/, '');
|
const href = '/' + notif.link.replace(/^\/+/, '');
|
||||||
const notifClass = notif.is_read == 0 ? "notification_item unread" : "notification_item";
|
const isUnread = notif.is_read == 0;
|
||||||
const iconHTML = notif.is_read == 0 ? '<i class="fa fa-exclamation-circle icon-unread mr-9"></i>' : '';
|
|
||||||
|
// Détecter le type à partir du début du message
|
||||||
|
let accentColor = '#7f8c8d';
|
||||||
|
let badgeColor = '#7f8c8d';
|
||||||
|
let typeLabel = 'Info';
|
||||||
|
let typeIcon = 'fa-bell';
|
||||||
|
|
||||||
|
const msg = notif.message || '';
|
||||||
|
if (msg.includes('💰') || msg.toLowerCase().includes('remise')) {
|
||||||
|
accentColor = '#f39c12'; badgeColor = '#e67e22'; typeLabel = 'Remise'; typeIcon = 'fa-tag';
|
||||||
|
} else if (msg.includes('📦') || msg.toLowerCase().includes('commande')) {
|
||||||
|
accentColor = '#3498db'; badgeColor = '#2980b9'; typeLabel = 'Commande'; typeIcon = 'fa-shopping-cart';
|
||||||
|
} else if (msg.includes('✅') || msg.toLowerCase().includes('acceptée') || msg.toLowerCase().includes('validée')) {
|
||||||
|
accentColor = '#27ae60'; badgeColor = '#219a52'; typeLabel = 'Accepté'; typeIcon = 'fa-check-circle';
|
||||||
|
} else if (msg.includes('❌') || msg.toLowerCase().includes('refusée')) {
|
||||||
|
accentColor = '#e74c3c'; badgeColor = '#c0392b'; typeLabel = 'Refusé'; typeIcon = 'fa-times-circle';
|
||||||
|
} else if (msg.toLowerCase().includes('livraison') || msg.toLowerCase().includes('remis')) {
|
||||||
|
accentColor = '#9b59b6'; badgeColor = '#8e44ad'; typeLabel = 'Livraison'; typeIcon = 'fa-truck';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formater la date lisiblement
|
||||||
|
let dateDisplay = notif.created_at || '';
|
||||||
|
try {
|
||||||
|
const d = new Date(notif.created_at);
|
||||||
|
if (!isNaN(d)) {
|
||||||
|
const now = new Date();
|
||||||
|
const diffMs = now - d;
|
||||||
|
const diffMn = Math.floor(diffMs / 60000);
|
||||||
|
const diffH = Math.floor(diffMn / 60);
|
||||||
|
if (diffMn < 1) dateDisplay = 'À l\'instant';
|
||||||
|
else if (diffMn < 60) dateDisplay = diffMn + ' min';
|
||||||
|
else if (diffH < 24) dateDisplay = diffH + 'h';
|
||||||
|
else dateDisplay = d.toLocaleDateString('fr-FR', {day:'2-digit', month:'2-digit'});
|
||||||
|
}
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
notificationHTML += `
|
notificationHTML += `
|
||||||
<a href="${href}"
|
<a href="${href}" class="notif-card ${isUnread ? 'notif-unread' : ''}" data-id="${notif.id}">
|
||||||
class="${notifClass}"
|
<div class="notif-accent" style="background:${accentColor};"></div>
|
||||||
data-id="${notif.id}"
|
<div class="notif-body">
|
||||||
style="font-size: 15px; display: flex; align-items: center; justify-content: space-between;">
|
<div class="notif-header">
|
||||||
<span style="display: flex; align-items: center; gap:10px;">
|
<span class="notif-type-badge" style="background:${badgeColor};">
|
||||||
${iconHTML} ${notif.message}
|
<i class="fa ${typeIcon}"></i> ${typeLabel}
|
||||||
</span>
|
</span>
|
||||||
<span class="float-right text-muted text-sm">${notif.created_at}</span>
|
<span class="notif-time"><i class="fa fa-clock-o"></i> ${dateDisplay}</span>
|
||||||
|
</div>
|
||||||
|
<div class="notif-message">${msg}</div>
|
||||||
|
</div>
|
||||||
|
${isUnread ? '<div class="notif-dot"></div>' : ''}
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
|
||||||
`;
|
`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (notificationHTML === '') {
|
||||||
|
notificationHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
$('#notificationList').html(notificationHTML);
|
$('#notificationList').html(notificationHTML);
|
||||||
$('#notificationHeader').text(data.length + ' Notifications');
|
|
||||||
|
const unreadLabel = notificationCount > 0
|
||||||
|
? `<i class="fa fa-bell"></i> ${notificationCount} non lue${notificationCount > 1 ? 's' : ''}`
|
||||||
|
: `<i class="fa fa-bell"></i> Notifications`;
|
||||||
|
$('#notificationHeader').html(unreadLabel);
|
||||||
|
|
||||||
if (notificationCount > 0) {
|
if (notificationCount > 0) {
|
||||||
$('#notificationCount').text(notificationCount).show();
|
$('#notificationCount').text(notificationCount).show();
|
||||||
@ -143,22 +320,17 @@ function fetchNotifications() {
|
|||||||
$('#markAllAsReadBtn').hide();
|
$('#markAllAsReadBtn').hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = document.querySelectorAll('.notification_item');
|
document.querySelectorAll('.notif-card').forEach(item => {
|
||||||
items.forEach(item => {
|
|
||||||
item.addEventListener('click', () => {
|
item.addEventListener('click', () => {
|
||||||
const notifId = item.dataset.id;
|
const notifId = item.dataset.id;
|
||||||
fetch("<?= base_url('notifications/markAsRead') ?>/" + notifId, {
|
fetch("<?= base_url('notifications/markAsRead') ?>/" + notifId, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" }
|
headers: { "Content-Type": "application/json" }
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(r => r.json())
|
||||||
.then(data => {
|
.catch(e => console.error(e));
|
||||||
console.log("Notification marked as read:", data);
|
|
||||||
})
|
|
||||||
.catch(error => console.error("Error:", error));
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
error: function(err) {
|
error: function(err) {
|
||||||
console.error('Error fetching notifications:', err);
|
console.error('Error fetching notifications:', err);
|
||||||
|
|||||||
@ -1,17 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "codeigniter4/framework",
|
"name": "app/motorbike",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"description": "The CodeIgniter framework v4",
|
"description": "MOTORBiKE - Application de gestion commerciale",
|
||||||
"homepage": "https://codeigniter.com",
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.4 || ^8.0",
|
"php": "^8.2",
|
||||||
|
"codeigniter4/framework": "^4.3",
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"ext-intl": "*",
|
"ext-intl": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"laminas/laminas-escaper": "^2.9",
|
|
||||||
"psr/log": "^1.1",
|
|
||||||
"firebase/php-jwt": "^6.11",
|
"firebase/php-jwt": "^6.11",
|
||||||
"kint-php/kint": "5.0",
|
"kint-php/kint": "5.0",
|
||||||
"phpoffice/phpspreadsheet": "^5.0"
|
"phpoffice/phpspreadsheet": "^5.0"
|
||||||
@ -46,7 +44,7 @@
|
|||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"CodeIgniter\\": "system/"
|
"App\\": "app/"
|
||||||
},
|
},
|
||||||
"exclude-from-classmap": [
|
"exclude-from-classmap": [
|
||||||
"**/Database/Migrations/**"
|
"**/Database/Migrations/**"
|
||||||
@ -56,6 +54,11 @@
|
|||||||
|
|
||||||
"test": "phpunit"
|
"test": "phpunit"
|
||||||
},
|
},
|
||||||
|
"config": {
|
||||||
|
"audit": {
|
||||||
|
"block-insecure": false
|
||||||
|
}
|
||||||
|
},
|
||||||
"support": {
|
"support": {
|
||||||
"forum": "http://forum.codeigniter.com/",
|
"forum": "http://forum.codeigniter.com/",
|
||||||
"source": "https://github.com/codeigniter4/CodeIgniter4",
|
"source": "https://github.com/codeigniter4/CodeIgniter4",
|
||||||
|
|||||||
@ -1,17 +1,34 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Check PHP version.
|
use CodeIgniter\Boot;
|
||||||
$minPhpVersion = '7.4'; // If you update this, don't forget to update `spark`.
|
use Config\Paths;
|
||||||
|
|
||||||
|
/*
|
||||||
|
*---------------------------------------------------------------
|
||||||
|
* CHECK PHP VERSION
|
||||||
|
*---------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$minPhpVersion = '8.2'; // If you update this, don't forget to update `spark`.
|
||||||
if (version_compare(PHP_VERSION, $minPhpVersion, '<')) {
|
if (version_compare(PHP_VERSION, $minPhpVersion, '<')) {
|
||||||
$message = sprintf(
|
$message = sprintf(
|
||||||
'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s',
|
'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s',
|
||||||
$minPhpVersion,
|
$minPhpVersion,
|
||||||
PHP_VERSION
|
PHP_VERSION,
|
||||||
);
|
);
|
||||||
|
|
||||||
exit($message);
|
header('HTTP/1.1 503 Service Unavailable.', true, 503);
|
||||||
|
echo $message;
|
||||||
|
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*---------------------------------------------------------------
|
||||||
|
* SET THE CURRENT DIRECTORY
|
||||||
|
*---------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
// Path to the front controller (this file)
|
// Path to the front controller (this file)
|
||||||
define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR);
|
define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR);
|
||||||
|
|
||||||
@ -29,59 +46,14 @@ if (getcwd() . DIRECTORY_SEPARATOR !== FCPATH) {
|
|||||||
* and fires up an environment-specific bootstrapping.
|
* and fires up an environment-specific bootstrapping.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Load our paths config file
|
// LOAD OUR PATHS CONFIG FILE
|
||||||
// This is the line that might need to be changed, depending on your folder structure.
|
// This is the line that might need to be changed, depending on your folder structure.
|
||||||
require FCPATH . '../app/Config/Paths.php';
|
require FCPATH . '../app/Config/Paths.php';
|
||||||
// ^^^ Change this line if you move your application folder
|
// ^^^ Change this line if you move your application folder
|
||||||
|
|
||||||
$paths = new Config\Paths();
|
$paths = new Paths();
|
||||||
|
|
||||||
// Location of the framework bootstrap file.
|
// LOAD THE FRAMEWORK BOOTSTRAP FILE
|
||||||
require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php';
|
require $paths->systemDirectory . '/Boot.php';
|
||||||
|
|
||||||
// Load environment settings from .env files into $_SERVER and $_ENV
|
exit(Boot::bootWeb($paths));
|
||||||
require_once SYSTEMPATH . 'Config/DotEnv.php';
|
|
||||||
(new CodeIgniter\Config\DotEnv(ROOTPATH))->load();
|
|
||||||
|
|
||||||
// Define ENVIRONMENT
|
|
||||||
if (! defined('ENVIRONMENT')) {
|
|
||||||
define('ENVIRONMENT', env('CI_ENVIRONMENT', 'development'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load Config Cache
|
|
||||||
// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();
|
|
||||||
// $factoriesCache->load('config');
|
|
||||||
// ^^^ Uncomment these lines if you want to use Config Caching.
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ---------------------------------------------------------------
|
|
||||||
* GRAB OUR CODEIGNITER INSTANCE
|
|
||||||
* ---------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* The CodeIgniter class contains the core functionality to make
|
|
||||||
* the application run, and does all the dirty work to get
|
|
||||||
* the pieces all working together.
|
|
||||||
*/
|
|
||||||
|
|
||||||
$app = Config\Services::codeigniter();
|
|
||||||
$app->initialize();
|
|
||||||
$context = is_cli() ? 'php-cli' : 'web';
|
|
||||||
$app->setContext($context);
|
|
||||||
|
|
||||||
/*
|
|
||||||
*---------------------------------------------------------------
|
|
||||||
* LAUNCH THE APPLICATION
|
|
||||||
*---------------------------------------------------------------
|
|
||||||
* Now that everything is set up, it's time to actually fire
|
|
||||||
* up the engines and make this app do its thang.
|
|
||||||
*/
|
|
||||||
|
|
||||||
$app->run();
|
|
||||||
|
|
||||||
// Save Config Cache
|
|
||||||
// $factoriesCache->save('config');
|
|
||||||
// ^^^ Uncomment this line if you want to use Config Caching.
|
|
||||||
|
|
||||||
// Exits the application, setting the exit code for CLI-based applications
|
|
||||||
// that might be watching.
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
|
|||||||
75
spark
75
spark
@ -4,35 +4,46 @@
|
|||||||
/**
|
/**
|
||||||
* This file is part of CodeIgniter 4 framework.
|
* This file is part of CodeIgniter 4 framework.
|
||||||
*
|
*
|
||||||
* (c) CodeIgniter Foundation <Conseil@codeigniter.com>
|
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||||
*
|
*
|
||||||
* For the full copyright and license information, please view
|
* For the full copyright and license information, please view
|
||||||
* the LICENSE file that was distributed with this source code.
|
* the LICENSE file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use CodeIgniter\Boot;
|
||||||
|
use Config\Paths;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
* CodeIgniter command-line tools
|
* CODEIGNITER COMMAND-LINE TOOLS
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
* The main entry point into the CLI system and allows you to run
|
* The main entry point into the CLI system and allows you to run
|
||||||
* commands and perform maintenance on your application.
|
* commands and perform maintenance on your application.
|
||||||
*
|
*/
|
||||||
* Because CodeIgniter can handle CLI requests as just another web request
|
|
||||||
* this class mainly acts as a passthru to the framework itself.
|
/*
|
||||||
|
*---------------------------------------------------------------
|
||||||
|
* CHECK SERVER API
|
||||||
|
*---------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Refuse to run when called from php-cgi
|
// Refuse to run when called from php-cgi
|
||||||
if (strpos(PHP_SAPI, 'cgi') === 0) {
|
if (str_starts_with(PHP_SAPI, 'cgi')) {
|
||||||
exit("The cli tool is not supported when running php-cgi. It needs php-cli to function!\n\n");
|
exit("The cli tool is not supported when running php-cgi. It needs php-cli to function!\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check PHP version.
|
/*
|
||||||
$minPhpVersion = '7.4'; // If you update this, don't forget to update `public/index.php`.
|
*---------------------------------------------------------------
|
||||||
|
* CHECK PHP VERSION
|
||||||
|
*---------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
$minPhpVersion = '8.2'; // If you update this, don't forget to update `public/index.php`.
|
||||||
if (version_compare(PHP_VERSION, $minPhpVersion, '<')) {
|
if (version_compare(PHP_VERSION, $minPhpVersion, '<')) {
|
||||||
$message = sprintf(
|
$message = sprintf(
|
||||||
'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s',
|
'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s',
|
||||||
$minPhpVersion,
|
$minPhpVersion,
|
||||||
PHP_VERSION
|
PHP_VERSION,
|
||||||
);
|
);
|
||||||
|
|
||||||
exit($message);
|
exit($message);
|
||||||
@ -42,12 +53,11 @@ if (version_compare(PHP_VERSION, $minPhpVersion, '<')) {
|
|||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
ini_set('display_errors', '1');
|
ini_set('display_errors', '1');
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* @var bool
|
*---------------------------------------------------------------
|
||||||
*
|
* SET THE CURRENT DIRECTORY
|
||||||
* @deprecated No longer in use. `CodeIgniter` has `$context` property.
|
*---------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
define('SPARKED', true);
|
|
||||||
|
|
||||||
// Path to the front controller
|
// Path to the front controller
|
||||||
define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR);
|
define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR);
|
||||||
@ -64,41 +74,14 @@ chdir(FCPATH);
|
|||||||
* and fires up an environment-specific bootstrapping.
|
* and fires up an environment-specific bootstrapping.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Load our paths config file
|
// LOAD OUR PATHS CONFIG FILE
|
||||||
// This is the line that might need to be changed, depending on your folder structure.
|
// This is the line that might need to be changed, depending on your folder structure.
|
||||||
require FCPATH . '../app/Config/Paths.php';
|
require FCPATH . '../app/Config/Paths.php';
|
||||||
// ^^^ Change this line if you move your application folder
|
// ^^^ Change this line if you move your application folder
|
||||||
|
|
||||||
$paths = new Config\Paths();
|
$paths = new Paths();
|
||||||
|
|
||||||
// Location of the framework bootstrap file.
|
// LOAD THE FRAMEWORK BOOTSTRAP FILE
|
||||||
require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php';
|
require $paths->systemDirectory . '/Boot.php';
|
||||||
|
|
||||||
// Load environment settings from .env files into $_SERVER and $_ENV
|
exit(Boot::bootSpark($paths));
|
||||||
require_once SYSTEMPATH . 'Config/DotEnv.php';
|
|
||||||
(new CodeIgniter\Config\DotEnv(ROOTPATH))->load();
|
|
||||||
|
|
||||||
// Define ENVIRONMENT
|
|
||||||
if (! defined('ENVIRONMENT')) {
|
|
||||||
define('ENVIRONMENT', env('CI_ENVIRONMENT', 'production'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grab our CodeIgniter
|
|
||||||
$app = Config\Services::codeigniter();
|
|
||||||
$app->initialize();
|
|
||||||
|
|
||||||
// Grab our Console
|
|
||||||
$console = new CodeIgniter\CLI\Console();
|
|
||||||
|
|
||||||
// Show basic information before we do anything else.
|
|
||||||
if (is_int($suppress = array_search('--no-header', $_SERVER['argv'], true))) {
|
|
||||||
unset($_SERVER['argv'][$suppress]); // @codeCoverageIgnore
|
|
||||||
$suppress = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$console->showHeader($suppress);
|
|
||||||
|
|
||||||
// fire off the command in the main framework.
|
|
||||||
$exit = $console->run();
|
|
||||||
|
|
||||||
exit(is_int($exit) ? $exit : EXIT_SUCCESS);
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user