Autosave: 20260519-173441

This commit is contained in:
Flatlogic Bot 2026-05-19 17:34:42 +00:00
parent 8d1b45365f
commit 2454573a89
2 changed files with 145 additions and 40 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

View File

@ -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'; ?>