Autosave: 20260519-173441
This commit is contained in:
parent
8d1b45365f
commit
2454573a89
Binary file not shown.
|
After Width: | Height: | Size: 228 KiB |
@ -118,15 +118,15 @@ $stmtEstados = $db->query("SELECT estado, COUNT(*) as total FROM pedidos p WHERE
|
||||
$estadosData = $stmtEstados->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// 7. Top Productos (Ajustado al periodo) - TOTAL
|
||||
$stmtTopProd = $db->query("SELECT producto, SUM(cantidad) as ventas FROM pedidos p WHERE $date_condition AND estado NOT IN ('RETORNADO', 'GESTIONES') GROUP BY producto ORDER BY ventas DESC LIMIT 10");
|
||||
$stmtTopProd = $db->query("SELECT producto, SUM(cantidad) as ventas FROM pedidos p WHERE $date_condition AND estado NOT IN ('RETORNADO', 'GESTIONES') GROUP BY producto ORDER BY ventas DESC");
|
||||
$topProductos = $stmtTopProd->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// 7b. Top Productos Contraentrega (Ajustado al periodo)
|
||||
$stmtTopProdCE = $db->query("SELECT producto, SUM(cantidad) as ventas FROM pedidos p WHERE $date_condition AND estado IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA') GROUP BY producto ORDER BY ventas DESC LIMIT 10");
|
||||
$stmtTopProdCE = $db->query("SELECT producto, SUM(cantidad) as ventas FROM pedidos p WHERE $date_condition AND estado IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA') GROUP BY producto ORDER BY ventas DESC");
|
||||
$topProductosCE = $stmtTopProdCE->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// 7c. Top Productos Provincia (Ajustado al periodo)
|
||||
$stmtTopProdProv = $db->query("SELECT producto, SUM(cantidad) as ventas FROM pedidos p WHERE $date_condition AND estado NOT IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA', 'RETORNADO', 'GESTIONES') GROUP BY producto ORDER BY ventas DESC LIMIT 10");
|
||||
$stmtTopProdProv = $db->query("SELECT producto, SUM(cantidad) as ventas FROM pedidos p WHERE $date_condition AND estado NOT IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA', 'RETORNADO', 'GESTIONES') GROUP BY producto ORDER BY ventas DESC");
|
||||
$topProductosProv = $stmtTopProdProv->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// 8. Ventas por Asesor (Ajustado al periodo)
|
||||
@ -194,7 +194,6 @@ $stmtTopDetalle = $db->query("
|
||||
WHERE $date_condition AND p.estado NOT IN ('RETORNADO', 'GESTIONES')
|
||||
GROUP BY p.producto
|
||||
ORDER BY total_cantidad DESC
|
||||
LIMIT 10
|
||||
");
|
||||
$topProductosDetalle = $stmtTopDetalle->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
@ -206,7 +205,6 @@ $stmtTopDetalleCE = $db->query("
|
||||
WHERE $date_condition AND p.estado IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA')
|
||||
GROUP BY p.producto
|
||||
ORDER BY total_cantidad DESC
|
||||
LIMIT 10
|
||||
");
|
||||
$topProductosDetalleCE = $stmtTopDetalleCE->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
@ -218,7 +216,6 @@ $stmtTopDetalleProv = $db->query("
|
||||
WHERE $date_condition AND p.estado NOT IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA', 'RETORNADO', 'GESTIONES')
|
||||
GROUP BY p.producto
|
||||
ORDER BY total_cantidad DESC
|
||||
LIMIT 10
|
||||
");
|
||||
$topProductosDetalleProv = $stmtTopDetalleProv->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
@ -235,7 +232,6 @@ $stmtProdRendimientoCE = $db->query("
|
||||
AND estado IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA', 'RETORNADO')
|
||||
GROUP BY producto
|
||||
ORDER BY total DESC
|
||||
LIMIT 10
|
||||
");
|
||||
$prodRendimientoCE = $stmtProdRendimientoCE->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
@ -252,10 +248,21 @@ $stmtProdRendimientoProv = $db->query("
|
||||
AND estado NOT IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA', 'RETORNADO')
|
||||
GROUP BY producto
|
||||
ORDER BY total DESC
|
||||
LIMIT 10
|
||||
");
|
||||
$prodRendimientoProv = $stmtProdRendimientoProv->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// 16. Top Upsells (Combinaciones de productos distintos)
|
||||
$stmtTopUpsell = $db->query("
|
||||
SELECT producto, COUNT(*) as total_pedidos, SUM(monto_total) as recaudo
|
||||
FROM pedidos p
|
||||
WHERE $date_condition
|
||||
AND producto LIKE '%,%'
|
||||
AND estado NOT IN ('RETORNADO', 'GESTIONES')
|
||||
GROUP BY producto
|
||||
ORDER BY total_pedidos DESC
|
||||
");
|
||||
$topUpsells = $stmtTopUpsell->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$canalesResumen = [
|
||||
'Provincia' => ['pedidos' => 0, 'monto' => 0, 'estados' => []],
|
||||
'Contraentrega' => ['pedidos' => 0, 'monto' => 0, 'estados' => []]
|
||||
@ -447,8 +454,8 @@ include 'layout_header.php';
|
||||
<h5 class="mb-0 text-primary"><i class="fas fa-chart-pie me-2"></i> Estados Provincia</h5>
|
||||
<span class="badge bg-primary text-white">Distribución Interna</span>
|
||||
</div>
|
||||
<div class="card-body d-flex flex-column align-items-center justify-content-center" style="min-height: 300px;">
|
||||
<div style="width: 100%; max-width: 450px;">
|
||||
<div class="card-body d-flex flex-column align-items-center justify-content-center" style="min-height: 350px;">
|
||||
<div style="width: 100%; max-width: 450px; height: 300px; position: relative;">
|
||||
<canvas id="provinciaPieChart"></canvas>
|
||||
</div>
|
||||
<div class="mt-3 text-center">
|
||||
@ -466,8 +473,8 @@ include 'layout_header.php';
|
||||
<h5 class="mb-0 text-warning"><i class="fas fa-chart-pie me-2"></i> Estados Contraentrega</h5>
|
||||
<span class="badge bg-warning text-dark">Distribución Interna</span>
|
||||
</div>
|
||||
<div class="card-body d-flex flex-column align-items-center justify-content-center" style="min-height: 300px;">
|
||||
<div style="width: 100%; max-width: 450px;">
|
||||
<div class="card-body d-flex flex-column align-items-center justify-content-center" style="min-height: 350px;">
|
||||
<div style="width: 100%; max-width: 450px; height: 300px; position: relative;">
|
||||
<canvas id="contraentregaPieChart"></canvas>
|
||||
</div>
|
||||
<div class="mt-3 text-center">
|
||||
@ -599,18 +606,20 @@ include 'layout_header.php';
|
||||
<div class="col-12 mb-4">
|
||||
<div class="card shadow h-100">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0 text-primary"><i class="fas fa-trophy me-2"></i> Top 10 Productos Más Vendidos (Total)</h5>
|
||||
<h5 class="mb-0 text-primary"><i class="fas fa-trophy me-2"></i> Productos Más Vendidos (Total)</h5>
|
||||
<span class="badge bg-primary">Rendimiento Global</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-12 mb-4">
|
||||
<canvas id="productosChart" style="height: 550px;"></canvas>
|
||||
<div style="position: relative; height: 550px;">
|
||||
<canvas id="productosChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="table-responsive">
|
||||
<div class="table-responsive" style="max-height: 400px; overflow-y: auto;">
|
||||
<table class="table table-hover table-sm align-middle">
|
||||
<thead class="table-light">
|
||||
<thead class="table-light sticky-top">
|
||||
<tr>
|
||||
<th>Producto</th>
|
||||
<th class="text-center">Cant.</th>
|
||||
@ -620,7 +629,7 @@ include 'layout_header.php';
|
||||
<tbody>
|
||||
<?php foreach ($topProductosDetalle as $prod): ?>
|
||||
<tr>
|
||||
<td class="fw-bold text-dark small" style="font-size: 0.85rem;"><?php echo htmlspecialchars(strlen($prod['producto']) > 35 ? substr($prod['producto'], 0, 35) . '...' : $prod['producto']); ?></td>
|
||||
<td class="fw-bold text-dark small" style="font-size: 0.85rem;"><?php echo htmlspecialchars($prod['producto']); ?></td>
|
||||
<td class="text-center">
|
||||
<span class="badge bg-light text-primary border border-primary px-3">
|
||||
<?php echo number_format($prod['total_cantidad']); ?>
|
||||
@ -641,20 +650,83 @@ include 'layout_header.php';
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SECCIÓN TOP UPSELL -->
|
||||
<div class="row">
|
||||
<div class="col-12 mb-4">
|
||||
<div class="card shadow h-100 border-left-success">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0 text-success"><i class="fas fa-plus-circle me-2"></i> Top Upsell: Combinaciones de Productos Distintos</h5>
|
||||
<span class="badge bg-success text-white">Estrategia de Venta Cruzada</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if (empty($topUpsells)): ?>
|
||||
<div class="text-center py-5">
|
||||
<i class="fas fa-shopping-basket fa-3x text-gray-300 mb-3"></i>
|
||||
<p class="text-muted">No se encontraron pedidos con combinaciones de productos distintos en este periodo.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="row">
|
||||
<div class="col-lg-7 mb-4">
|
||||
<div style="position: relative; height: 400px;">
|
||||
<canvas id="upsellChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<div class="table-responsive" style="max-height: 400px; overflow-y: auto;">
|
||||
<table class="table table-hover table-sm align-middle">
|
||||
<thead class="table-light sticky-top">
|
||||
<tr>
|
||||
<th>Combinación de Productos</th>
|
||||
<th class="text-center">Pedidos</th>
|
||||
<th class="text-end">Recaudo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($topUpsells as $upsell): ?>
|
||||
<tr>
|
||||
<td class="small fw-bold text-dark">
|
||||
<?php
|
||||
$parts = explode(', ', $upsell['producto']);
|
||||
foreach($parts as $index => $part) {
|
||||
echo '<span class="badge bg-light text-dark border mb-1">' . htmlspecialchars($part) . '</span>' . ($index < count($parts)-1 ? ' <i class="fas fa-plus text-muted small mx-1"></i> ' : '');
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="badge rounded-pill bg-success px-3"><?php echo $upsell['total_pedidos']; ?></span>
|
||||
</td>
|
||||
<td class="text-end fw-bold text-success">
|
||||
S/ <?php echo number_format($upsell['recaudo'], 2); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Top Productos Contraentrega -->
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card shadow h-100 border-left-warning">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0 text-warning">Top 10 Contraentrega</h5>
|
||||
<h5 class="mb-0 text-warning">Productos Contraentrega</h5>
|
||||
<span class="badge bg-warning text-dark">Motorizado</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<canvas id="productosCEChart" class="mb-4" style="height: 450px;"></canvas>
|
||||
<div style="position: relative; height: 450px;" class="mb-4">
|
||||
<canvas id="productosCEChart"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<div class="table-responsive" style="max-height: 350px; overflow-y: auto;">
|
||||
<table class="table table-hover table-sm align-middle">
|
||||
<thead class="table-light">
|
||||
<thead class="table-light sticky-top">
|
||||
<tr>
|
||||
<th>Producto</th>
|
||||
<th class="text-center">Cant.</th>
|
||||
@ -664,7 +736,7 @@ include 'layout_header.php';
|
||||
<tbody>
|
||||
<?php foreach ($topProductosDetalleCE as $prod): ?>
|
||||
<tr>
|
||||
<td class="fw-bold text-dark small" style="font-size: 0.75rem;"><?php echo htmlspecialchars(strlen($prod['producto']) > 25 ? substr($prod['producto'], 0, 25) . '...' : $prod['producto']); ?></td>
|
||||
<td class="fw-bold text-dark small" style="font-size: 0.75rem;"><?php echo htmlspecialchars($prod['producto']); ?></td>
|
||||
<td class="text-center">
|
||||
<span class="badge bg-light text-warning border border-warning">
|
||||
<?php echo number_format($prod['total_cantidad']); ?>
|
||||
@ -686,15 +758,17 @@ include 'layout_header.php';
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card shadow h-100 border-left-info">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0 text-info">Top 10 Provincia</h5>
|
||||
<h5 class="mb-0 text-info">Productos Provincia</h5>
|
||||
<span class="badge bg-info text-white">Agencias</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<canvas id="productosProvChart" class="mb-4" style="height: 450px;"></canvas>
|
||||
<div style="position: relative; height: 450px;" class="mb-4">
|
||||
<canvas id="productosProvChart"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<div class="table-responsive" style="max-height: 350px; overflow-y: auto;">
|
||||
<table class="table table-hover table-sm align-middle">
|
||||
<thead class="table-light">
|
||||
<thead class="table-light sticky-top">
|
||||
<tr>
|
||||
<th>Producto</th>
|
||||
<th class="text-center">Cant.</th>
|
||||
@ -704,7 +778,7 @@ include 'layout_header.php';
|
||||
<tbody>
|
||||
<?php foreach ($topProductosDetalleProv as $prod): ?>
|
||||
<tr>
|
||||
<td class="fw-bold text-dark small" style="font-size: 0.75rem;"><?php echo htmlspecialchars(strlen($prod['producto']) > 25 ? substr($prod['producto'], 0, 25) . '...' : $prod['producto']); ?></td>
|
||||
<td class="fw-bold text-dark small" style="font-size: 0.75rem;"><?php echo htmlspecialchars($prod['producto']); ?></td>
|
||||
<td class="text-center">
|
||||
<span class="badge bg-light text-info border border-info">
|
||||
<?php echo number_format($prod['total_cantidad']); ?>
|
||||
@ -729,10 +803,10 @@ include 'layout_header.php';
|
||||
<div class="card shadow border-left-primary h-100">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0 text-primary"><i class="fas fa-chart-bar me-2"></i> Rendimiento Producto (Provincia)</h5>
|
||||
<span class="badge bg-primary text-white">Top 10</span>
|
||||
<span class="badge bg-primary text-white">Todos los productos</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div style="height: 350px;">
|
||||
<div style="position: relative; height: 350px;">
|
||||
<canvas id="rendimientoProdProvChart"></canvas>
|
||||
</div>
|
||||
<div class="mt-3 small text-muted text-center">
|
||||
@ -747,10 +821,10 @@ include 'layout_header.php';
|
||||
<div class="card shadow border-left-warning h-100">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0 text-warning"><i class="fas fa-chart-bar me-2"></i> Rendimiento Producto (Contraentrega)</h5>
|
||||
<span class="badge bg-warning text-dark">Top 10</span>
|
||||
<span class="badge bg-warning text-dark">Todos los productos</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div style="height: 350px;">
|
||||
<div style="position: relative; height: 350px;">
|
||||
<canvas id="rendimientoProdCEChart"></canvas>
|
||||
</div>
|
||||
<div class="mt-3 small text-muted text-center">
|
||||
@ -979,7 +1053,7 @@ include 'layout_header.php';
|
||||
new Chart(ctxProductos, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: <?php echo json_encode(array_map(function($p) { return strlen($p['producto']) > 30 ? substr($p['producto'], 0, 30) . '...' : $p['producto']; }, $topProductos)); ?>,
|
||||
labels: <?php echo json_encode(array_column($topProductos, 'producto')); ?>,
|
||||
datasets: [{
|
||||
label: 'Unidades',
|
||||
data: <?php echo json_encode(array_column($topProductos, 'ventas')); ?>,
|
||||
@ -1028,7 +1102,7 @@ include 'layout_header.php';
|
||||
new Chart(ctxProductosCE, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: <?php echo json_encode(array_map(function($p) { return strlen($p['producto']) > 15 ? substr($p['producto'], 0, 15) . '...' : $p['producto']; }, $topProductosCE)); ?>,
|
||||
labels: <?php echo json_encode(array_column($topProductosCE, 'producto')); ?>,
|
||||
datasets: [{
|
||||
label: 'Unidades',
|
||||
data: <?php echo json_encode(array_column($topProductosCE, 'ventas')); ?>,
|
||||
@ -1072,7 +1146,7 @@ include 'layout_header.php';
|
||||
new Chart(ctxProductosProv, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: <?php echo json_encode(array_map(function($p) { return strlen($p['producto']) > 15 ? substr($p['producto'], 0, 15) . '...' : $p['producto']; }, $topProductosProv)); ?>,
|
||||
labels: <?php echo json_encode(array_column($topProductosProv, 'producto')); ?>,
|
||||
datasets: [{
|
||||
label: 'Unidades',
|
||||
data: <?php echo json_encode(array_column($topProductosProv, 'ventas')); ?>,
|
||||
@ -1116,9 +1190,7 @@ include 'layout_header.php';
|
||||
new Chart(ctxRendimientoCE, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: <?php echo json_encode(array_map(function($p) {
|
||||
return strlen($p['producto']) > 15 ? substr($p['producto'], 0, 15) . '...' : $p['producto'];
|
||||
}, $prodRendimientoCE)); ?>,
|
||||
labels: <?php echo json_encode(array_column($prodRendimientoCE, 'producto')); ?>,
|
||||
datasets: [
|
||||
{
|
||||
label: 'Exitosa ✅',
|
||||
@ -1175,9 +1247,7 @@ include 'layout_header.php';
|
||||
new Chart(ctxRendimientoProv, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: <?php echo json_encode(array_map(function($p) {
|
||||
return strlen($p['producto']) > 15 ? substr($p['producto'], 0, 15) . '...' : $p['producto'];
|
||||
}, $prodRendimientoProv)); ?>,
|
||||
labels: <?php echo json_encode(array_column($prodRendimientoProv, 'producto')); ?>,
|
||||
datasets: [
|
||||
{
|
||||
label: 'Completado ✅',
|
||||
@ -1269,6 +1339,41 @@ include 'layout_header.php';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Gráfico de Upsell
|
||||
<?php if (!empty($topUpsells)): ?>
|
||||
const ctxUpsell = document.getElementById('upsellChart').getContext('2d');
|
||||
new Chart(ctxUpsell, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: <?php echo json_encode(array_column($topUpsells, 'producto')); ?>,
|
||||
datasets: [{
|
||||
label: 'Número de Pedidos',
|
||||
data: <?php echo json_encode(array_column($topUpsells, 'total_pedidos')); ?>,
|
||||
backgroundColor: '#198754',
|
||||
borderRadius: 5,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
datalabels: {
|
||||
anchor: 'end',
|
||||
align: 'right',
|
||||
color: '#000',
|
||||
font: { weight: 'bold' }
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: { beginAtZero: true, title: { display: true, text: 'Cantidad de Pedidos' } },
|
||||
y: { ticks: { font: { size: 10 } } }
|
||||
}
|
||||
}
|
||||
});
|
||||
<?php endif; ?>
|
||||
</script>
|
||||
|
||||
<?php include 'layout_footer.php'; ?>
|
||||
Loading…
x
Reference in New Issue
Block a user