You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

743 lines
24 KiB

<!-- application/Views/securite/history.php -->
<style>
.validation-summary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
overflow: hidden;
margin: 20px 0;
}
.validation-summary .box-header {
background: rgba(255, 255, 255, 0.95);
border-bottom: 3px solid #667eea;
padding: 20px 25px;
}
.validation-summary .box-title {
color: #667eea;
font-size: 22px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.validation-summary .box-body {
background: #ffffff;
padding: 35px 25px;
}
.stat-card {
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
border-radius: 12px;
padding: 25px 15px;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
border-left: 5px solid #2196f3;
text-align: center;
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.stat-number {
font-size: 36px;
font-weight: 800;
color: #1976d2;
margin: 10px 0;
}
.stat-label {
font-size: 14px;
font-weight: 600;
text-transform: uppercase;
color: #1565c0;
letter-spacing: 0.5px;
}
.badge-validated {
background-color: #4caf50;
color: white;
padding: 5px 10px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
}
.table-responsive {
border-radius: 10px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
#historyTable thead {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
#historyTable thead th {
border: none !important;
font-weight: 600;
text-transform: uppercase;
font-size: 13px;
letter-spacing: 0.5px;
}
#historyTable tbody tr {
transition: all 0.2s ease;
}
#historyTable tbody tr:hover {
background-color: #f5f5f5;
transform: scale(1.01);
}
.moto-image {
width: 80px;
height: 60px;
object-fit: cover;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.agent-name {
color: #667eea;
font-weight: 600;
}
.validation-date {
color: #6c757d;
font-size: 13px;
}
.filter-section {
background: #f8f9fa;
padding: 20px;
border-radius: 10px;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
</style>
<div class="content-wrapper">
<!-- Content Header -->
<section class="content-header">
<h1>
Historique des Livraisons
<small>Suivi des sorties validées par magasin</small>
</h1>
<ol class="breadcrumb">
<li><a href="<?= base_url('#') ?>"><i class="fa fa-dashboard"></i> Accueil</a></li>
<li><a href="<?= base_url('validateSecurite') ?>"><i class="fa fa-shield"></i> Livraisons</a></li>
<li class="active">Historique</li>
</ol>
</section>
<!-- Main content -->
<section class="content">
<div id="messages"></div>
<?php if (session()->getFlashdata('success')): ?>
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<?= session()->getFlashdata('success') ?>
</div>
<?php endif; ?>
<!-- Statistiques -->
<div class="row">
<div class="col-md-12">
<div class="validation-summary">
<div class="box-header">
<h3 class="box-title">
<i class="fa fa-bar-chart"></i> Résumé des Livraisons
<span id="storeNameDisplay" style="color: #764ba2; margin-left: 10px;"></span>
</h3>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-4">
<div class="stat-card">
<i class="fa fa-check-circle" style="font-size: 40px; color: #2196f3;"></i>
<div class="stat-number" id="totalValidations">0</div>
<div class="stat-label">Total Livraisons</div>
</div>
</div>
<div class="col-md-4">
<div class="stat-card">
<i class="fa fa-calendar" style="font-size: 40px; color: #2196f3;"></i>
<div class="stat-number" id="todayValidations">0</div>
<div class="stat-label">Livraisons Aujourd'hui</div>
</div>
</div>
<div class="col-md-4">
<div class="stat-card">
<i class="fa fa-motorcycle" style="font-size: 40px; color: #2196f3;"></i>
<div class="stat-number" id="monthValidations">0</div>
<div class="stat-label">Livraisons ce Mois</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Filtres -->
<div class="row">
<div class="col-md-12">
<div class="filter-section">
<div class="row">
<div class="col-md-3">
<label for="filterStartDate">Date de début</label>
<input type="date" id="filterStartDate" class="form-control">
</div>
<div class="col-md-3">
<label for="filterEndDate">Date de fin</label>
<input type="date" id="filterEndDate" class="form-control">
</div>
<!-- ✅ FILTRE PAR MAGASIN -->
<div class="col-md-3">
<label for="filterStore">Magasin</label>
<select id="filterStore" class="form-control">
<option value="">Tous les magasins</option>
<?php if (isset($stores) && is_array($stores)): ?>
<?php foreach ($stores as $store): ?>
<option value="<?= $store['id'] ?>"><?= $store['name'] ?></option>
<?php endforeach; ?>
<?php endif; ?>
</select>
</div>
<div class="col-md-3">
<label>&nbsp;</label><br>
<button id="btnFilter" class="btn btn-primary">
<i class="fa fa-filter"></i> Filtrer
</button>
<button id="btnReset" class="btn btn-warning">
<i class="fa fa-refresh"></i> Réinitialiser
</button>
<button id="btnExport" class="btn btn-success">
<i class="fa fa-file-excel-o"></i> Exporter
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Tableau historique -->
<div class="row">
<div class="col-md-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">
<i class="fa fa-history"></i> Historique des Livraisons
</h3>
</div>
<div class="box-body">
<div class="table-responsive">
<table id="historyTable" class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Image</th>
<th>N° Facture</th>
<th>Désignation</th>
<th>UGS</th>
<th>Marque</th>
<th>Client</th>
<th>Magasin</th>
<th>Agent Sécurité</th>
<th>Date Validation</th>
<th>Statut</th>
<th>Quantité</th>
</tr>
</thead>
<tbody>
<!-- Les données seront chargées par DataTables -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
<!-- Modal Détails -->
<div class="modal fade" id="detailsModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;">
<button type="button" class="close" data-dismiss="modal" style="color: white;">&times;</button>
<h4 class="modal-title">
<i class="fa fa-info-circle"></i> Détails de la Validation
</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-4 text-center">
<img id="detailImage" class="img-responsive img-thumbnail" src="" alt="Image moto" style="max-height: 250px;">
</div>
<div class="col-md-8">
<h4 style="border-bottom: 2px solid #667eea; padding-bottom: 10px; margin-bottom: 20px;">
<i class="fa fa-motorcycle"></i> Informations Produit
</h4>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>N° Facture:</strong></div>
<div class="col-xs-6"><span id="detailBillNo"></span></div>
</div>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>Désignation:</strong></div>
<div class="col-xs-6"><span id="detailDesignation"></span></div>
</div>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>UGS:</strong></div>
<div class="col-xs-6"><span id="detailUGS"></span></div>
</div>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>Marque:</strong></div>
<div class="col-xs-6"><span id="detailMarque"></span></div>
</div>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>N° de Série:</strong></div>
<div class="col-xs-6"><span id="detailSerie"></span></div>
</div>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>Magasin:</strong></div>
<div class="col-xs-6"><span id="detailStore"></span></div>
</div>
<h4 style="border-bottom: 2px solid #667eea; padding-bottom: 10px; margin: 20px 0;">
<i class="fa fa-user"></i> Informations Client
</h4>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>Nom:</strong></div>
<div class="col-xs-6"><span id="detailClientName"></span></div>
</div>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>Téléphone:</strong></div>
<div class="col-xs-6"><span id="detailClientPhone"></span></div>
</div>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>Adresse:</strong></div>
<div class="col-xs-6"><span id="detailClientAddress"></span></div>
</div>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>CIN:</strong></div>
<div class="col-xs-6"><span id="detailClientCIN"></span></div>
</div>
<h4 style="border-bottom: 2px solid #667eea; padding-bottom: 10px; margin: 20px 0;">
<i class="fa fa-shield"></i> Informations Validation
</h4>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>Agent Sécurité:</strong></div>
<div class="col-xs-6"><span id="detailAgent" class="agent-name"></span></div>
</div>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>Date Validation:</strong></div>
<div class="col-xs-6"><span id="detailDateValidation"></span></div>
</div>
<div class="row" style="margin-bottom: 15px;">
<div class="col-xs-6"><strong>Statut:</strong></div>
<div class="col-xs-6"><span id="detailStatut"></span></div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
<i class="fa fa-times"></i> Fermer
</button>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<script>
$(function() {
$("#securiteNav").addClass('active');
// Configuration DataTable en français
$.extend(true, $.fn.dataTable.defaults, {
language: {
sProcessing: "Traitement en cours...",
sSearch: "Rechercher&nbsp;:",
sLengthMenu: "Afficher _MENU_ éléments",
sInfo: "Affichage de _START_ à _END_ sur _TOTAL_ éléments",
sInfoEmpty: "Aucun élément à afficher",
sInfoFiltered: "(filtré de _MAX_ éléments au total)",
sLoadingRecords: "Chargement en cours...",
sZeroRecords: "Aucune validation trouvée",
sEmptyTable: "Aucune donnée disponible",
oPaginate: {
sFirst: "Premier",
sPrevious: "Précédent",
sNext: "Suivant",
sLast: "Dernier"
}
}
});
// ✅ INITIALISER LES DATES À AUJOURD'HUI PAR DÉFAUT
var today = new Date().toISOString().split('T')[0];
$('#filterStartDate').val(today);
$('#filterEndDate').val(today);
// ✅ CHARGER LES STATISTIQUES DU MOIS AU DÉMARRAGE
loadStatisticsForCurrentMonth();
// ✅ INITIALISATION DATATABLE
var historyTable = $('#historyTable').DataTable({
ajax: {
url: '<?= base_url('reports/detail/fetchSecuritePerformances') ?>',
type: 'GET',
data: function(d) {
d.startDate = $('#filterStartDate').val();
d.endDate = $('#filterEndDate').val();
d.store_id = $('#filterStore').val();
console.log('📤 Filtres envoyés:', {
startDate: d.startDate,
endDate: d.endDate,
store_id: d.store_id
});
},
dataSrc: function(json) {
console.log('📥 Données reçues:', json.data.length, 'lignes');
return json.data;
},
error: function(xhr, error, code) {
console.error('❌ Erreur DataTables:', error);
alert('Erreur lors du chargement des données');
}
},
columns: [
{ data: 0, orderable: false, render: function(data) {
return '<img src="' + data + '" class="moto-image" alt="Moto">';
}},
{ data: 1 },
{ data: 2 },
{ data: 3 },
{ data: 4 },
{ data: 5 },
{ data: 7, render: function(data) {
return '<span class="badge badge-info">' + data + '</span>';
}},
{ data: 6, render: function(data) {
return '<span class="agent-name">' + data + '</span>';
}},
{ data: 8, render: function(data) {
return '<span class="validation-date">' + data + '</span>';
}},
{ data: 9, orderable: false },
{ data: 10, orderable: true, className: 'text-center', render: function(data) {
return '<span class="badge badge-primary">' + data + '</span>';
}}
],
order: [[8, 'desc']],
pageLength: 10,
lengthMenu: [[5, 10, 25, 50, -1], [5, 10, 25, 50, "Tout"]]
});
// ✅ BOUTON FILTRER - RECHARGE TABLEAU + STATISTIQUES
$('#btnFilter').on('click', function() {
console.log('🔍 Bouton Filtrer cliqué');
var startDate = $('#filterStartDate').val();
var endDate = $('#filterEndDate').val();
var storeId = $('#filterStore').val();
console.log('Dates:', startDate, 'à', endDate);
console.log('Store ID:', storeId || 'Tous');
historyTable.ajax.reload();
// ✅ RECHARGER LES STATISTIQUES SELON LA PÉRIODE ET LE MAGASIN FILTRÉS
loadStatisticsForFilteredPeriod(startDate, endDate, storeId);
});
// ✅ BOUTON RÉINITIALISER
$('#btnReset').on('click', function() {
console.log('🔄 Réinitialisation des filtres');
var today = new Date().toISOString().split('T')[0];
$('#filterStartDate').val(today);
$('#filterEndDate').val(today);
$('#filterStore').val('');
$('#storeNameDisplay').text('');
historyTable.ajax.reload();
loadStatisticsForCurrentMonth();
});
// ✅ CHANGEMENT DE MAGASIN - METTRE À JOUR LES STATS
$('#filterStore').on('change', function() {
var storeId = $(this).val();
var storeName = $(this).find('option:selected').text();
var startDate = $('#filterStartDate').val();
var endDate = $('#filterEndDate').val();
console.log('🏪 Magasin changé:', storeName);
// Afficher le nom du magasin dans le titre
if (storeId) {
$('#storeNameDisplay').text('- ' + storeName);
} else {
$('#storeNameDisplay').text('');
}
// Recharger automatiquement le tableau et les stats
historyTable.ajax.reload();
if (startDate && endDate) {
loadStatisticsForFilteredPeriod(startDate, endDate, storeId);
} else {
loadStatisticsForCurrentMonth();
}
});
// ✅ FONCTION : CHARGER LES STATISTIQUES DU MOIS EN COURS
function loadStatisticsForCurrentMonth() {
console.log('📊 Chargement des statistiques du mois en cours...');
var now = new Date();
var firstDay = new Date(now.getFullYear(), now.getMonth(), 1);
var lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0);
var startDate = firstDay.toISOString().split('T')[0];
var endDate = lastDay.toISOString().split('T')[0];
loadStatisticsForFilteredPeriod(startDate, endDate, '');
}
// ✅ FONCTION : CHARGER LES STATISTIQUES POUR UNE PÉRIODE ET UN MAGASIN DONNÉS
function loadStatisticsForFilteredPeriod(startDate, endDate, storeId) {
console.log('📊 Chargement des statistiques pour:', startDate, 'au', endDate, 'Store ID:', storeId || 'TOUS');
$.ajax({
url: '<?= base_url('reports/detail/fetchSecuritePerformances') ?>',
type: 'GET',
data: {
startDate: startDate,
endDate: endDate,
store_id: storeId
},
success: function(response) {
console.log('✅ Statistiques chargées:', response.data.length, 'lignes');
calculateStatistics(response.data, startDate, endDate, storeId);
},
error: function(xhr, error) {
console.error('❌ Erreur chargement statistiques:', error);
}
});
}
// ✅ FONCTION POUR CALCULER LES STATISTIQUES (AVEC FILTRAGE PAR MAGASIN)
function calculateStatistics(data, filterStartDate, filterEndDate, filterStoreId) {
var today = new Date();
today.setHours(0, 0, 0, 0);
var todayCount = 0;
var monthCount = 0;
var filteredMonth = null;
var filteredYear = null;
if (filterStartDate && filterEndDate) {
var startDateObj = new Date(filterStartDate);
var endDateObj = new Date(filterEndDate);
if (startDateObj.getMonth() === endDateObj.getMonth() &&
startDateObj.getFullYear() === endDateObj.getFullYear()) {
filteredMonth = startDateObj.getMonth();
filteredYear = startDateObj.getFullYear();
}
}
$.each(data, function(i, item) {
var itemDateStr = item[8]; // Date de validation
if (itemDateStr && itemDateStr !== 'N/A') {
try {
var date;
if (itemDateStr.includes('/')) {
var parts = itemDateStr.split(' ')[0].split('/');
date = new Date(parts[2], parts[1] - 1, parts[0]);
} else {
date = new Date(itemDateStr);
}
if (!isNaN(date.getTime())) {
date.setHours(0, 0, 0, 0);
// Compter aujourd'hui
if (date.getTime() === today.getTime()) {
todayCount++;
}
// Compter le mois filtré (ou mois en cours)
if (filteredMonth !== null) {
if (date.getMonth() === filteredMonth && date.getFullYear() === filteredYear) {
monthCount++;
}
} else {
if (date.getMonth() === today.getMonth() && date.getFullYear() === today.getFullYear()) {
monthCount++;
}
}
}
} catch (e) {
console.warn('Date invalide:', itemDateStr, e);
}
}
});
// ✅ METTRE À JOUR LES COMPTEURS
$('#totalValidations').text(monthCount);
$('#todayValidations').text(todayCount);
$('#monthValidations').text(monthCount);
console.log('📈 Statistiques:', {
store_id: filterStoreId || 'TOUS',
total: monthCount,
aujourd_hui: todayCount,
ce_mois: monthCount,
periode_filtree: filterStartDate + ' au ' + filterEndDate
});
}
// ✅ BOUTON EXPORT EXCEL
$('#btnExport').on('click', function() {
var wb = XLSX.utils.book_new();
var data = [];
data.push([
'N° Facture',
'Désignation',
'UGS',
'Marque',
'Client',
'Magasin',
'Agent Sécurité',
'Date Validation',
'Statut',
'Quantité'
]);
historyTable.rows({ search: 'applied' }).every(function() {
var rowData = this.data();
data.push([
rowData[1],
rowData[2],
rowData[3],
rowData[4],
rowData[5],
rowData[7],
rowData[6],
rowData[8],
'VALIDÉE',
rowData[10]
]);
});
var ws = XLSX.utils.aoa_to_sheet(data);
ws['!cols'] = [
{ wch: 15 }, { wch: 30 }, { wch: 15 }, { wch: 20 }, { wch: 25 },
{ wch: 20 }, { wch: 25 }, { wch: 20 }, { wch: 12 }, { wch: 10 }
];
XLSX.utils.book_append_sheet(wb, ws, "Historique");
var today = new Date().toISOString().split('T')[0];
var filename = 'historique_livraisons_' + today + '.xlsx';
XLSX.writeFile(wb, filename);
console.log('✅ Export Excel réalisé:', filename);
});
});
// ✅ FONCTION POUR AFFICHER LES DÉTAILS
function viewDetails(id) {
$.get('<?= base_url('reports/detail/getSecuriteValidationDetails') ?>/' + id, function(data) {
$('#detailImage').attr('src', data[0]);
$('#detailBillNo').text(data[1]);
$('#detailDesignation').text(data[2]);
$('#detailUGS').text(data[3]);
$('#detailMarque').text(data[4]);
$('#detailSerie').text(data[3]);
$('#detailStore').text(data[7]);
$('#detailClientName').text(data[5]);
$('#detailClientPhone').text(data[12]);
$('#detailClientAddress').text(data[13]);
$('#detailClientCIN').text(data[14]);
$('#detailAgent').text(data[6]);
$('#detailDateValidation').text(formatDate(data[8]));
$('#detailStatut').html(data[9]);
var additionalInfo = '';
if (data[15] && data[15] !== 'N/A') {
additionalInfo += '<div class="row" style="margin-bottom: 15px;">';
additionalInfo += '<div class="col-xs-6"><strong>N° de Moteur:</strong></div>';
additionalInfo += '<div class="col-xs-6"><span>' + data[15] + '</span></div>';
additionalInfo += '</div>';
}
if (data[16] && data[16] !== 'N/A') {
additionalInfo += '<div class="row" style="margin-bottom: 15px;">';
additionalInfo += '<div class="col-xs-6"><strong>N° de Châssis:</strong></div>';
additionalInfo += '<div class="col-xs-6"><span>' + data[16] + '</span></div>';
additionalInfo += '</div>';
}
if (additionalInfo) {
$('#detailSerie').closest('.row').after(additionalInfo);
}
$('#detailsModal').modal('show');
}, 'json');
}
// ✅ FONCTION POUR FORMATER LA DATE
function formatDate(dateString) {
if (!dateString || dateString === 'N/A') return 'N/A';
try {
var date;
if (dateString.includes('/')) {
var parts = dateString.split(' ');
var dateParts = parts[0].split('/');
var timeParts = parts[1] ? parts[1].split(':') : ['00', '00'];
date = new Date(dateParts[2], dateParts[1] - 1, dateParts[0], timeParts[0], timeParts[1]);
} else {
date = new Date(dateString);
}
if (isNaN(date.getTime())) {
return dateString;
}
var options = {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
};
return date.toLocaleDateString('fr-FR', options);
} catch (e) {
console.warn('Erreur formatage date:', dateString, e);
return dateString;
}
}
</script>