fix: corrections et améliorations du 01-04-2026
## Recouvrement - Liste triée par date décroissante - Pop-up de confirmation anti-doublons - Affichage avec permission "Voir" seule ## Mise à jour produit - Correction erreur "Column count doesn't match" (triggers MySQL corrigés) - Formulaire corrigé (action, catégorie, champs null) - Catégorie et date d'arrivage correctement préremplis - Historique affiche le nom de l'utilisateur qui modifie ## Espace commercial - Colonne "Disponibilité" ajoutée avec statut "En attente de livraison" - Bouton panier caché pour les motos commandées - Surbrillance jaune pour les motos en attente ## Notifications - Caissière reçoit les notifications via notifCommande - notifSortieCaisse réservé à Direction/Admin ## Avances - Colonne "N° Série" ajoutée dans toutes les listes - Compteurs sur les boutons Incomplètes/Complètes ## Facture / BL - Total, Remise, Total à payer affichés - "Ariary" ne se répète plus - Prix individuel par moto - Impression automatique : 1 produit = Facture, 2+ = BL - Remise multiple : colonne product changée en TEXT ## Rapports - Filtre par date dans le rapport stock - Filtre par commercial et mécanicien dans les performances - Correction rapport stock (GROUP BY marque) - Liens absolus (correction erreur 404) ## Sidebar - Marge en haut supprimée (production) - Padding en bas ajouté pour scroll complet Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a195d24e78
commit
fe80b9c4f8
@ -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']);
|
||||||
|
|
||||||
|
|||||||
@ -129,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>";
|
||||||
@ -139,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,
|
||||||
@ -147,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
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -116,13 +116,14 @@ 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) {
|
||||||
@ -131,6 +132,7 @@ private function buildDataRow($value, $product, $isAdmin, $isCommerciale, $isCai
|
|||||||
$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,
|
||||||
@ -228,12 +231,13 @@ private function fetchAvanceDataGeneric($methodName = 'getAllAvanceData')
|
|||||||
|
|
||||||
$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']));
|
||||||
|
|
||||||
|
$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) {
|
||||||
@ -242,6 +246,7 @@ private function fetchAvanceDataGeneric($methodName = 'getAllAvanceData')
|
|||||||
$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, ',', ' '),
|
||||||
$status,
|
$status,
|
||||||
@ -252,6 +257,7 @@ private function fetchAvanceDataGeneric($methodName = 'getAllAvanceData')
|
|||||||
$result['data'][] = [
|
$result['data'][] = [
|
||||||
$value['avance_id'],
|
$value['avance_id'],
|
||||||
$productName,
|
$productName,
|
||||||
|
$productSku,
|
||||||
number_format((int)$value['avance_amount'], 0, ',', ' '),
|
number_format((int)$value['avance_amount'], 0, ',', ' '),
|
||||||
$status,
|
$status,
|
||||||
$date_time,
|
$date_time,
|
||||||
|
|||||||
@ -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'] ?? ''
|
||||||
];
|
];
|
||||||
|
|||||||
@ -663,16 +663,21 @@ class OrderController extends AdminController
|
|||||||
|
|
||||||
$Notification->notifyGroupsByPermissionAllStores('notifRemise', $message, 'remise/');
|
$Notification->notifyGroupsByPermissionAllStores('notifRemise', $message, 'remise/');
|
||||||
|
|
||||||
} else {
|
// Notifier la Caissière (notifCommande) et l'admin/direction (notifSortieCaisse)
|
||||||
// Commande sans remise
|
$messageCommande = "📦 Nouvelle commande (avec remise) à traiter : {$bill_no}<br>" .
|
||||||
$Notification->notifyGroupsByPermission(
|
|
||||||
'notifSortieCaisse',
|
|
||||||
"📦 Nouvelle commande à valider : {$bill_no}<br>" .
|
|
||||||
"Client : {$data['customer_name']}<br>" .
|
"Client : {$data['customer_name']}<br>" .
|
||||||
"Montant : " . number_format($gross_amount, 0, ',', ' ') . " Ar",
|
"Montant demandé : " . number_format($discount, 0, ',', ' ') . " Ar<br>" .
|
||||||
(int)$users['store_id'],
|
"En attente de validation remise";
|
||||||
"orders"
|
$Notification->notifyGroupsByPermission('notifCommande', $messageCommande, (int)$users['store_id'], "orders");
|
||||||
);
|
$Notification->notifyGroupsByPermission('notifSortieCaisse', $messageCommande, (int)$users['store_id'], "orders");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Commande sans remise - notifier Caissière (notifCommande) et admin/direction (notifSortieCaisse)
|
||||||
|
$messageCommande = "📦 Nouvelle commande à traiter : {$bill_no}<br>" .
|
||||||
|
"Client : {$data['customer_name']}<br>" .
|
||||||
|
"Montant : " . number_format($gross_amount, 0, ',', ' ') . " Ar";
|
||||||
|
$Notification->notifyGroupsByPermission('notifCommande', $messageCommande, (int)$users['store_id'], "orders");
|
||||||
|
$Notification->notifyGroupsByPermission('notifSortieCaisse', $messageCommande, (int)$users['store_id'], "orders");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($users["group_name"] != "COMMERCIALE") {
|
if ($users["group_name"] != "COMMERCIALE") {
|
||||||
@ -1724,20 +1729,15 @@ public function update(int $id)
|
|||||||
public function printDiv(int $id)
|
public function printDiv(int $id)
|
||||||
{
|
{
|
||||||
$Orders = new Orders();
|
$Orders = new Orders();
|
||||||
|
$OrderItems = new OrderItems();
|
||||||
$order = $Orders->getOrdersData($id);
|
$order = $Orders->getOrdersData($id);
|
||||||
|
$items = $OrderItems->getOrdersItemData($id);
|
||||||
|
|
||||||
$docType = $order['document_type'] ?? 'facture';
|
// Plus d'1 produit = BL, 1 seul produit = Facture
|
||||||
|
if (count($items) > 1) {
|
||||||
// Rediriger vers la bonne méthode selon le type
|
return $this->print7($id); // Bon de livraison
|
||||||
switch($docType) {
|
} else {
|
||||||
case 'facture':
|
return $this->print5($id); // Facture
|
||||||
return $this->print31($id); // Factures individuelles
|
|
||||||
case 'bl':
|
|
||||||
return $this->print7($id); // Bon de livraison
|
|
||||||
case 'both':
|
|
||||||
return $this->print31($id); // Factures + Bon de livraison
|
|
||||||
default:
|
|
||||||
return $this->print31($id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2007,23 +2007,26 @@ public function print5(int $id)
|
|||||||
|
|
||||||
$discount = (float) $order['discount'];
|
$discount = (float) $order['discount'];
|
||||||
$grossAmount = (float) $order['gross_amount'];
|
$grossAmount = (float) $order['gross_amount'];
|
||||||
$totalTTC = ($discount > 0) ? $discount : $grossAmount;
|
$totalAPayer = ($discount > 0) ? $discount : $grossAmount;
|
||||||
$inWords = strtoupper($this->numberToWords((int) round($totalTTC)));
|
$remiseAmount = ($discount > 0) ? ($grossAmount - $discount) : 0;
|
||||||
|
$inWords = strtoupper($this->numberToWords((int) round($totalAPayer)));
|
||||||
|
|
||||||
// Construire les lignes du tableau
|
// Construire les lignes du tableau
|
||||||
$tableRows = '';
|
$tableRows = '';
|
||||||
|
$totalPrixIndividuels = 0;
|
||||||
foreach ($items as $it) {
|
foreach ($items as $it) {
|
||||||
$details = $this->getOrderItemDetails($it);
|
$details = $this->getOrderItemDetails($it);
|
||||||
if (!$details) continue;
|
if (!$details) continue;
|
||||||
|
|
||||||
$qty = isset($it['qty']) ? (int)$it['qty'] : 1;
|
$qty = isset($it['qty']) ? (int)$it['qty'] : 1;
|
||||||
$prix = ($discount > 0) ? ($discount / $qty) : $details['prix'];
|
$prixItem = $details['prix'] * $qty;
|
||||||
|
$totalPrixIndividuels += $prixItem;
|
||||||
|
|
||||||
$tableRows .= '<tr>
|
$tableRows .= '<tr>
|
||||||
<td>'.esc($details['marque']).'</td>
|
<td>'.esc($details['marque']).'</td>
|
||||||
<td>'.esc($details['numero_chassis']).'</td>
|
<td>'.esc($details['numero_chassis']).'</td>
|
||||||
<td>'.esc($details['puissance']).'</td>
|
<td>'.esc($details['puissance']).'</td>
|
||||||
<td>'.number_format($prix * $qty, 0, ' ', ' ').' MGA</td>
|
<td>'.number_format($prixItem, 0, ' ', ' ').'</td>
|
||||||
</tr>';
|
</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2043,7 +2046,7 @@ public function print5(int $id)
|
|||||||
$companyPhone = esc($company['phone']);
|
$companyPhone = esc($company['phone']);
|
||||||
$companyPhone2 = esc($company['phone2']);
|
$companyPhone2 = esc($company['phone2']);
|
||||||
$companyAddress = esc($company['address'] ?? '');
|
$companyAddress = esc($company['address'] ?? '');
|
||||||
$totalFormatted = number_format($totalTTC, 0, ' ', ' ');
|
$totalFormatted = number_format($totalAPayer, 0, ' ', ' ');
|
||||||
$qrValue = "FACTURE N° {$billNo} | Client: {$customerName} | Montant: {$totalFormatted} MGA | Date: {$today} | Facebook: https://www.facebook.com/MOTORBIKESTORE2021/";
|
$qrValue = "FACTURE N° {$billNo} | Client: {$customerName} | Montant: {$totalFormatted} MGA | Date: {$today} | Facebook: https://www.facebook.com/MOTORBIKESTORE2021/";
|
||||||
|
|
||||||
$html = '<!DOCTYPE html>
|
$html = '<!DOCTYPE html>
|
||||||
@ -2058,7 +2061,8 @@ public function print5(int $id)
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
font-size: 11px;
|
font-size: 13px;
|
||||||
|
line-height: 1.3;
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2084,32 +2088,33 @@ public function print5(int $id)
|
|||||||
|
|
||||||
/* Header */
|
/* Header */
|
||||||
.f-title {
|
.f-title {
|
||||||
font-size: 22px;
|
font-size: 24px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.f-company {
|
.f-company {
|
||||||
font-size: 10px;
|
font-size: 12px;
|
||||||
line-height: 1.5;
|
line-height: 1.3;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.f-company strong { font-size: 12px; }
|
.f-company strong { font-size: 14px; }
|
||||||
|
|
||||||
.f-doit {
|
.f-doit {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 12px;
|
font-size: 14px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.f-client {
|
.f-client {
|
||||||
font-size: 10px;
|
font-size: 12px;
|
||||||
|
line-height: 1.3;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.f-client .field { margin: 2px 0; }
|
.f-client .field { margin: 3px 0; }
|
||||||
|
|
||||||
/* Table */
|
/* Table */
|
||||||
.f-table {
|
.f-table {
|
||||||
@ -2121,9 +2126,9 @@ public function print5(int $id)
|
|||||||
.f-table th, .f-table td {
|
.f-table th, .f-table td {
|
||||||
border-left: 2px solid #000;
|
border-left: 2px solid #000;
|
||||||
border-right: 2px solid #000;
|
border-right: 2px solid #000;
|
||||||
padding: 6px 8px;
|
padding: 8px 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 10px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.f-table th {
|
.f-table th {
|
||||||
@ -2132,7 +2137,7 @@ public function print5(int $id)
|
|||||||
border-bottom: 2px solid #000;
|
border-bottom: 2px solid #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.f-table td { height: 28px; }
|
.f-table td { height: 30px; }
|
||||||
|
|
||||||
.f-table tbody tr:last-child td {
|
.f-table tbody tr:last-child td {
|
||||||
border-bottom: 2px solid #000;
|
border-bottom: 2px solid #000;
|
||||||
@ -2140,7 +2145,8 @@ public function print5(int $id)
|
|||||||
|
|
||||||
/* Total en lettres */
|
/* Total en lettres */
|
||||||
.f-words {
|
.f-words {
|
||||||
font-size: 10px;
|
font-size: 12px;
|
||||||
|
line-height: 1.3;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2160,7 +2166,7 @@ public function print5(int $id)
|
|||||||
|
|
||||||
.f-sig-box .sig-label {
|
.f-sig-box .sig-label {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 11px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Date + N° + QR en bas */
|
/* Date + N° + QR en bas */
|
||||||
@ -2172,7 +2178,7 @@ public function print5(int $id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
.f-bottom .f-date-info {
|
.f-bottom .f-date-info {
|
||||||
font-size: 10px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.f-bottom canvas {
|
.f-bottom canvas {
|
||||||
@ -2196,13 +2202,13 @@ public function print5(int $id)
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-bottom: 2px dashed #aaa;
|
border-bottom: 2px dashed #aaa;
|
||||||
line-height: 1.6;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cond-box:last-child { border-bottom: none; }
|
.cond-box:last-child { border-bottom: none; }
|
||||||
|
|
||||||
.cond-title {
|
.cond-title {
|
||||||
font-size: 14px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
@ -2212,7 +2218,8 @@ public function print5(int $id)
|
|||||||
.cond-box ul {
|
.cond-box ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 10px;
|
font-size: 12px;
|
||||||
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cond-box li {
|
.cond-box li {
|
||||||
@ -2261,6 +2268,8 @@ public function print5(int $id)
|
|||||||
$qrId = 'qr_recto_'.$i;
|
$qrId = 'qr_recto_'.$i;
|
||||||
$html .= '
|
$html .= '
|
||||||
<div class="facture-box">
|
<div class="facture-box">
|
||||||
|
<div class="f-title" style="text-align:center;">FACTURE</div>
|
||||||
|
|
||||||
<div style="display:flex; justify-content:space-between; align-items:flex-start; margin-bottom:8px;">
|
<div style="display:flex; justify-content:space-between; align-items:flex-start; margin-bottom:8px;">
|
||||||
<div class="f-company" style="margin-bottom:0;">
|
<div class="f-company" style="margin-bottom:0;">
|
||||||
<strong>'.$companyName.'</strong><br>
|
<strong>'.$companyName.'</strong><br>
|
||||||
@ -2269,15 +2278,13 @@ public function print5(int $id)
|
|||||||
Contact : '.$companyPhone.' / '.$companyPhone2.'<br>
|
Contact : '.$companyPhone.' / '.$companyPhone2.'<br>
|
||||||
'.$companyAddress.'
|
'.$companyAddress.'
|
||||||
</div>
|
</div>
|
||||||
<div style="text-align:right; font-size:10px;">
|
<div style="text-align:right; font-size:12px;">
|
||||||
<div>DATE : '.$today.'</div>
|
<div>DATE : '.$today.'</div>
|
||||||
<div>N° : '.$billNo.'</div>
|
<div>N° : '.$billNo.'</div>
|
||||||
<canvas id="'.$qrId.'" style="margin-top:5px;"></canvas>
|
<canvas id="'.$qrId.'" style="margin-top:5px;"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="f-title" style="text-align:center;">FACTURE</div>
|
|
||||||
|
|
||||||
<div class="f-doit">DOIT</div>
|
<div class="f-doit">DOIT</div>
|
||||||
|
|
||||||
<div class="f-client">
|
<div class="f-client">
|
||||||
@ -2302,7 +2309,14 @@ public function print5(int $id)
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="f-words">
|
<div class="f-words">
|
||||||
<strong>Arrête à la somme de :</strong> '.$inWords.' Ariary
|
<strong>Total :</strong> '.number_format($totalPrixIndividuels, 0, ' ', ' ').' Ariary<br>';
|
||||||
|
|
||||||
|
if ($remiseAmount > 0) {
|
||||||
|
$html .= '<strong>Remise :</strong> -'.number_format($remiseAmount, 0, ' ', ' ').' Ariary<br>
|
||||||
|
<strong>Total à payer :</strong> '.number_format($totalAPayer, 0, ' ', ' ').' Ariary<br>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= '<strong>Arrête à la somme de :</strong> '.$inWords.'
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="f-signatures">
|
<div class="f-signatures">
|
||||||
@ -2532,22 +2546,26 @@ public function print7(int $id)
|
|||||||
|
|
||||||
$discount = (float) $order['discount'];
|
$discount = (float) $order['discount'];
|
||||||
$grossAmount = (float) $order['gross_amount'];
|
$grossAmount = (float) $order['gross_amount'];
|
||||||
$totalTTC = ($discount > 0) ? $discount : $grossAmount;
|
$totalAPayer = ($discount > 0) ? $discount : $grossAmount;
|
||||||
|
$remiseAmount = ($discount > 0) ? ($grossAmount - $discount) : 0;
|
||||||
|
$inWords = strtoupper($this->numberToWords((int) round($totalAPayer)));
|
||||||
|
|
||||||
// Construire les lignes du tableau
|
// Construire les lignes du tableau - prix individuel de chaque moto
|
||||||
$tableRows = '';
|
$tableRows = '';
|
||||||
|
$totalPrixIndividuels = 0;
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
$details = $this->getOrderItemDetails($item);
|
$details = $this->getOrderItemDetails($item);
|
||||||
if (!$details) continue;
|
if (!$details) continue;
|
||||||
|
|
||||||
$qty = isset($item['qty']) ? (int)$item['qty'] : 1;
|
$qty = isset($item['qty']) ? (int)$item['qty'] : 1;
|
||||||
$prix = ($discount > 0) ? ($discount / $qty) : $details['prix'];
|
$prixItem = $details['prix'] * $qty;
|
||||||
|
$totalPrixIndividuels += $prixItem;
|
||||||
|
|
||||||
$tableRows .= '<tr>
|
$tableRows .= '<tr>
|
||||||
<td>'.esc($details['marque']).'</td>
|
<td>'.esc($details['marque']).'</td>
|
||||||
<td>'.esc($details['numero_moteur']).'</td>
|
<td>'.esc($details['numero_moteur']).'</td>
|
||||||
<td>'.esc($details['puissance']).'</td>
|
<td>'.esc($details['puissance']).'</td>
|
||||||
<td>'.number_format($prix * $qty, 0, '', ' ').'</td>
|
<td>'.number_format($prixItem, 0, '', ' ').'</td>
|
||||||
</tr>';
|
</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2573,8 +2591,8 @@ public function print7(int $id)
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
line-height: 1.5;
|
line-height: 1.3;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2596,12 +2614,12 @@ public function print7(int $id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bl-company {
|
.bl-company {
|
||||||
font-size: 12px;
|
font-size: 13px;
|
||||||
line-height: 1.6;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bl-company strong {
|
.bl-company strong {
|
||||||
font-size: 15px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bl-title-block {
|
.bl-title-block {
|
||||||
@ -2629,11 +2647,12 @@ public function print7(int $id)
|
|||||||
/* Client info */
|
/* Client info */
|
||||||
.bl-client {
|
.bl-client {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bl-client .field {
|
.bl-client .field {
|
||||||
margin: 3px 0;
|
margin: 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bl-client .field strong {
|
.bl-client .field strong {
|
||||||
@ -2643,7 +2662,7 @@ public function print7(int $id)
|
|||||||
|
|
||||||
.bl-doit {
|
.bl-doit {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 14px;
|
font-size: 15px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2651,29 +2670,24 @@ public function print7(int $id)
|
|||||||
.bl-table {
|
.bl-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
flex: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bl-table th, .bl-table td {
|
.bl-table th, .bl-table td {
|
||||||
border-left: 2px solid #000;
|
border-left: 2px solid #000;
|
||||||
border-right: 2px solid #000;
|
border-right: 2px solid #000;
|
||||||
padding: 10px 15px;
|
padding: 5px 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bl-table th {
|
.bl-table th {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-top: 2px solid #000;
|
border-top: 2px solid #000;
|
||||||
border-bottom: 2px solid #000;
|
border-bottom: 2px solid #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bl-table td {
|
|
||||||
height: 35px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bl-table tbody tr:last-child td {
|
.bl-table tbody tr:last-child td {
|
||||||
border-bottom: 2px solid #000;
|
border-bottom: 2px solid #000;
|
||||||
}
|
}
|
||||||
@ -2684,7 +2698,8 @@ public function print7(int $id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bl-total {
|
.bl-total {
|
||||||
font-size: 14px;
|
font-size: 15px;
|
||||||
|
line-height: 1.3;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2758,7 +2773,14 @@ public function print7(int $id)
|
|||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<div class="bl-footer">
|
<div class="bl-footer">
|
||||||
<div class="bl-total">
|
<div class="bl-total">
|
||||||
<strong>Arrête à la somme de :</strong> '.number_format($totalTTC, 0, '', ' ').' Ariary
|
<strong>Total :</strong> '.number_format($totalPrixIndividuels, 0, '', ' ').' Ariary<br>';
|
||||||
|
|
||||||
|
if ($remiseAmount > 0) {
|
||||||
|
$html .= '<strong>Remise :</strong> -'.number_format($remiseAmount, 0, '', ' ').' Ariary<br>
|
||||||
|
<strong>Total à payer :</strong> '.number_format($totalAPayer, 0, '', ' ').' Ariary<br>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= '<strong>Arrête à la somme de :</strong> '.$inWords.'
|
||||||
</div>
|
</div>
|
||||||
<div class="bl-signatures">
|
<div class="bl-signatures">
|
||||||
<div class="bl-sig-box">
|
<div class="bl-sig-box">
|
||||||
@ -2775,7 +2797,7 @@ public function print7(int $id)
|
|||||||
<script>
|
<script>
|
||||||
new QRious({
|
new QRious({
|
||||||
element: document.getElementById("qrcode"),
|
element: document.getElementById("qrcode"),
|
||||||
value: "BON DE LIVRAISON\\nN° '.esc($order['bill_no']).'\\nClient: '.esc($order['customer_name']).'\\nMontant: '.number_format($totalTTC, 0, '', ' ').' Ar\\nDate: '.$today.'\\nFacebook: https://www.facebook.com/MOTORBIKESTORE2021/",
|
value: "BON DE LIVRAISON\\nN° '.esc($order['bill_no']).'\\nClient: '.esc($order['customer_name']).'\\nMontant: '.number_format($totalAPayer, 0, '', ' ').' Ar\\nDate: '.$today.'\\nFacebook: https://www.facebook.com/MOTORBIKESTORE2021/",
|
||||||
size: 90,
|
size: 90,
|
||||||
level: "H"
|
level: "H"
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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 = '';
|
||||||
@ -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'),
|
||||||
@ -297,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();
|
||||||
@ -316,32 +326,32 @@ class ProductCOntroller extends AdminController
|
|||||||
$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 (strtolower($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 ----
|
||||||
@ -367,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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -201,7 +201,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) {
|
||||||
@ -251,10 +251,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 +279,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']),
|
||||||
|
|||||||
@ -274,15 +274,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);
|
||||||
@ -605,7 +605,7 @@ class Orders extends Model
|
|||||||
return $order;
|
return $order;
|
||||||
}
|
}
|
||||||
|
|
||||||
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')
|
||||||
@ -615,7 +615,6 @@ class Orders extends Model
|
|||||||
->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);
|
||||||
@ -625,11 +624,14 @@ class Orders extends Model
|
|||||||
$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();
|
||||||
|
|||||||
@ -62,6 +62,23 @@ class Products extends Model
|
|||||||
->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) {
|
||||||
|
|||||||
@ -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>
|
||||||
@ -96,6 +101,7 @@ $isCaissier = isset($users['group_name']) && in_array($users['group_name'], ['Ca
|
|||||||
<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,6 +554,7 @@ $(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) {
|
||||||
@ -542,6 +581,10 @@ $(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);
|
||||||
@ -552,6 +595,7 @@ $(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) {
|
||||||
@ -587,6 +631,7 @@ $(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) {
|
||||||
@ -617,10 +662,11 @@ $(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',
|
||||||
|
'N° Série',
|
||||||
'Avance',
|
'Avance',
|
||||||
'Reste à payer',
|
'Reste à payer',
|
||||||
'Date',
|
'Date',
|
||||||
@ -653,6 +699,7 @@ $('#avance_order').on('click', function() {
|
|||||||
rebuildTableHeaders([
|
rebuildTableHeaders([
|
||||||
'#',
|
'#',
|
||||||
'Produit',
|
'Produit',
|
||||||
|
'N° Série',
|
||||||
'Avance',
|
'Avance',
|
||||||
'Statut',
|
'Statut',
|
||||||
'Date',
|
'Date',
|
||||||
@ -662,6 +709,7 @@ $('#avance_order').on('click', function() {
|
|||||||
var completedUserColumns = [
|
var completedUserColumns = [
|
||||||
{ title: "#" },
|
{ title: "#" },
|
||||||
{ title: "Produit" },
|
{ title: "Produit" },
|
||||||
|
{ title: "N° Série" },
|
||||||
{ title: "Avance" },
|
{ title: "Avance" },
|
||||||
{ title: "Statut" },
|
{ title: "Statut" },
|
||||||
{ title: "Date" }
|
{ title: "Date" }
|
||||||
@ -695,6 +743,7 @@ $('#avance_expired').on('click', function() {
|
|||||||
rebuildTableHeaders([
|
rebuildTableHeaders([
|
||||||
'#',
|
'#',
|
||||||
'Produit',
|
'Produit',
|
||||||
|
'N° Série',
|
||||||
'Avance',
|
'Avance',
|
||||||
'Reste à payer',
|
'Reste à payer',
|
||||||
'Date',
|
'Date',
|
||||||
@ -714,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é');
|
||||||
@ -1582,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');
|
||||||
@ -1601,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>
|
||||||
@ -75,6 +75,7 @@
|
|||||||
<th>Produit</th>
|
<th>Produit</th>
|
||||||
<th>SKU</th>
|
<th>SKU</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,
|
"data": 5,
|
||||||
"width": "10%",
|
"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,
|
||||||
|
|||||||
@ -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 ======
|
||||||
|
|||||||
@ -25,7 +25,8 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-default">Envoyer</button>
|
<button type="submit" class="btn btn-default">Envoyer</button>
|
||||||
<a href="detail/stock" class="btn btn-sm btn-success">Détails</a>
|
<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>
|
||||||
</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>
|
||||||
|
|
||||||
@ -188,7 +196,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 +206,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 +217,7 @@
|
|||||||
|
|
||||||
manageTable3 = $('#export1').DataTable({
|
manageTable3 = $('#export1').DataTable({
|
||||||
ajax: {
|
ajax: {
|
||||||
url: 'fetctDataStock2/' + 0,
|
url: 'fetchDataStock2/' + 0,
|
||||||
dataSrc: 'data'
|
dataSrc: 'data'
|
||||||
},
|
},
|
||||||
order: [],
|
order: [],
|
||||||
@ -226,8 +234,8 @@
|
|||||||
let filterValue = filterBtn.value === "TOUS" ? "0" : filterBtn.value;
|
let filterValue = filterBtn.value === "TOUS" ? "0" : filterBtn.value;
|
||||||
|
|
||||||
// Update the DataTable dynamically without reinitialization
|
// Update the DataTable dynamically without reinitialization
|
||||||
manageTable.ajax.url('fetctData/' + filterValue).load();
|
manageTable.ajax.url('fetchData/' + filterValue).load();
|
||||||
manageTable2.ajax.url('fetctDataStock/' + filterValue).load();
|
manageTable2.ajax.url('fetchDataStock/' + filterValue).load();
|
||||||
});
|
});
|
||||||
|
|
||||||
let productsSold = <?= $ventes ?>;
|
let productsSold = <?= $ventes ?>;
|
||||||
@ -249,6 +257,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);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -200,7 +200,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Image</th>
|
<th>Image</th>
|
||||||
<th>UGS</th>
|
<th>N° SERIE </th>
|
||||||
<th>Désignation</th>
|
<th>Désignation</th>
|
||||||
<th>Statut</th>
|
<th>Statut</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
@ -272,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>
|
||||||
|
|||||||
@ -278,6 +278,7 @@ body {
|
|||||||
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-top: 0 !important;
|
||||||
|
padding-bottom: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-sidebar .logo {
|
.main-sidebar .logo {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user