diff --git a/dashboard_principal.php b/dashboard_principal.php index b45ebeae..6842a377 100644 --- a/dashboard_principal.php +++ b/dashboard_principal.php @@ -118,15 +118,36 @@ $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"); +$stmtTopProd = $db->query("SELECT + CASE WHEN producto LIKE '%,%' THEN CONCAT('COMBO ', cantidad, ': ', producto) ELSE producto END as producto, + SUM(cantidad) as ventas, + SUM(monto_total) as monto + FROM pedidos p + WHERE $date_condition AND estado NOT IN ('RETORNADO', 'GESTIONES') + GROUP BY producto + ORDER BY monto 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"); +$stmtTopProdCE = $db->query("SELECT + CASE WHEN producto LIKE '%,%' THEN CONCAT('COMBO ', cantidad, ': ', producto) ELSE producto END as producto, + SUM(cantidad) as ventas, + SUM(monto_total) as monto + FROM pedidos p + WHERE $date_condition AND estado IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA') + GROUP BY producto + ORDER BY monto 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"); +$stmtTopProdProv = $db->query("SELECT + CASE WHEN producto LIKE '%,%' THEN CONCAT('COMBO ', cantidad, ': ', producto) ELSE producto END as producto, + SUM(cantidad) as ventas, + SUM(monto_total) as monto + FROM pedidos p + WHERE $date_condition AND estado NOT IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA', 'RETORNADO', 'GESTIONES') + GROUP BY producto + ORDER BY monto DESC"); $topProductosProv = $stmtTopProdProv->fetchAll(PDO::FETCH_ASSOC); // 8. Ventas por Asesor (Ajustado al periodo) @@ -188,41 +209,53 @@ $detalleCanalRaw = $stmtDetalleCanal->fetchAll(PDO::FETCH_ASSOC); // 13. Top Productos Detallado (Para la tabla) - TOTAL $stmtTopDetalle = $db->query(" - SELECT p.producto, SUM(p.cantidad) as total_cantidad, SUM(p.monto_total) as monto_total, AVG(pr.costo) as costo_promedio + SELECT + CASE WHEN p.producto LIKE '%,%' THEN CONCAT('COMBO ', p.cantidad, ': ', p.producto) ELSE p.producto END as producto, + SUM(p.cantidad) as total_cantidad, + SUM(p.monto_total) as monto_total, + AVG(pr.costo) as costo_promedio FROM pedidos p LEFT JOIN products pr ON p.producto = pr.nombre WHERE $date_condition AND p.estado NOT IN ('RETORNADO', 'GESTIONES') - GROUP BY p.producto - ORDER BY total_cantidad DESC + GROUP BY producto + ORDER BY monto_total DESC "); $topProductosDetalle = $stmtTopDetalle->fetchAll(PDO::FETCH_ASSOC); // 13b. Top Productos Detallado Contraentrega $stmtTopDetalleCE = $db->query(" - SELECT p.producto, SUM(p.cantidad) as total_cantidad, SUM(p.monto_total) as monto_total, AVG(pr.costo) as costo_promedio + SELECT + CASE WHEN p.producto LIKE '%,%' THEN CONCAT('COMBO ', p.cantidad, ': ', p.producto) ELSE p.producto END as producto, + SUM(p.cantidad) as total_cantidad, + SUM(p.monto_total) as monto_total, + AVG(pr.costo) as costo_promedio FROM pedidos p LEFT JOIN products pr ON p.producto = pr.nombre WHERE $date_condition AND p.estado IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA') - GROUP BY p.producto - ORDER BY total_cantidad DESC + GROUP BY producto + ORDER BY monto_total DESC "); $topProductosDetalleCE = $stmtTopDetalleCE->fetchAll(PDO::FETCH_ASSOC); // 13c. Top Productos Detallado Provincia $stmtTopDetalleProv = $db->query(" - SELECT p.producto, SUM(p.cantidad) as total_cantidad, SUM(p.monto_total) as monto_total, AVG(pr.costo) as costo_promedio + SELECT + CASE WHEN p.producto LIKE '%,%' THEN CONCAT('COMBO ', p.cantidad, ': ', p.producto) ELSE p.producto END as producto, + SUM(p.cantidad) as total_cantidad, + SUM(p.monto_total) as monto_total, + AVG(pr.costo) as costo_promedio FROM pedidos p LEFT JOIN products pr ON p.producto = pr.nombre WHERE $date_condition AND p.estado NOT IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA', 'RETORNADO', 'GESTIONES') - GROUP BY p.producto - ORDER BY total_cantidad DESC + GROUP BY producto + ORDER BY monto_total DESC "); $topProductosDetalleProv = $stmtTopDetalleProv->fetchAll(PDO::FETCH_ASSOC); // 14. Rendimiento de Productos en Contraentrega (Para Gráfica de Barras Apiladas) $stmtProdRendimientoCE = $db->query(" SELECT - producto, + CASE WHEN producto LIKE '%,%' THEN CONCAT('COMBO ', cantidad, ': ', producto) ELSE producto END as producto, COUNT(CASE WHEN estado = 'ENTREGA EXITOSA' THEN 1 END) as exitosas, COUNT(CASE WHEN estado = 'RETORNADO' THEN 1 END) as retornados, COUNT(CASE WHEN estado = 'RUTA_CONTRAENTREGA' THEN 1 END) as en_ruta, @@ -238,7 +271,7 @@ $prodRendimientoCE = $stmtProdRendimientoCE->fetchAll(PDO::FETCH_ASSOC); // 15. Rendimiento de Productos en Provincia $stmtProdRendimientoProv = $db->query(" SELECT - producto, + CASE WHEN producto LIKE '%,%' THEN CONCAT('COMBO ', cantidad, ': ', producto) ELSE producto END as producto, COUNT(CASE WHEN estado = 'COMPLETADO ✅' THEN 1 END) as completados, COUNT(CASE WHEN estado = 'GESTIONES' THEN 1 END) as gestiones, COUNT(CASE WHEN estado IN ('ROTULADO 📦', 'EN TRANSITO 🚛', 'EN DESTINO 🏬') THEN 1 END) as en_proceso, @@ -253,13 +286,16 @@ $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 + SELECT + CONCAT('COMBO ', cantidad, ': ', producto) as 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 + GROUP BY producto, cantidad + ORDER BY recaudo DESC "); $topUpsells = $stmtTopUpsell->fetchAll(PDO::FETCH_ASSOC); @@ -650,67 +686,6 @@ include 'layout_header.php'; - -
-
-
-
-
Top Upsell: Combinaciones de Productos Distintos
- Estrategia de Venta Cruzada -
-
- -
- -

No se encontraron pedidos con combinaciones de productos distintos en este periodo.

-
- -
-
-
- -
-
-
-
- - - - - - - - - - - - - - - - - -
Combinación de ProductosPedidosRecaudo
- $part) { - echo '' . htmlspecialchars($part) . '' . ($index < count($parts)-1 ? ' ' : ''); - } - ?> - - - - S/ -
-
-
-
- -
-
-
-
-
@@ -797,6 +772,73 @@ include 'layout_header.php';
+ +
+
+
+
+
Top Upsell: Combinaciones de Productos Distintos
+ Estrategia de Venta Cruzada +
+
+ +
+ +

No se encontraron pedidos con combinaciones de productos distintos en este periodo.

+
+ +
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + +
Combinación de ProductosPedidosRecaudo
+ ' . htmlspecialchars($parts_combo[0]) . ' '; + $displayName = $parts_combo[1]; + } + $parts = explode(', ', $displayName); + foreach($parts as $index => $part) { + echo '' . htmlspecialchars($part) . '' . ($index < count($parts)-1 ? ' ' : ''); + } + ?> + + + + S/ +
+
+
+
+ +
+
+
+
+
@@ -1055,8 +1097,8 @@ include 'layout_header.php'; data: { labels: , datasets: [{ - label: 'Unidades', - data: , + label: 'Monto Total (S/)', + data: , backgroundColor: '#0d6efd', borderRadius: 5, barPercentage: 0.7 @@ -1073,7 +1115,8 @@ include 'layout_header.php'; align: 'top', color: '#000', offset: 5, - font: { size: 13, weight: 'bold' } + font: { size: 13, weight: 'bold' }, + formatter: (value) => 'S/ ' + new Intl.NumberFormat('es-PE').format(value) } }, scales: { @@ -1083,7 +1126,7 @@ include 'layout_header.php'; drawBorder: false, color: 'rgba(0,0,0,0.05)' }, - title: { display: true, text: 'Unidades Vendidas', font: { weight: 'bold' } } + title: { display: true, text: 'Monto Total (Soles)', font: { weight: 'bold' } } }, x: { grid: { display: false }, @@ -1104,8 +1147,8 @@ include 'layout_header.php'; data: { labels: , datasets: [{ - label: 'Unidades', - data: , + label: 'Monto Total (S/)', + data: , backgroundColor: '#ffc107', borderRadius: 5, barPercentage: 0.7 @@ -1121,13 +1164,15 @@ include 'layout_header.php'; anchor: 'end', align: 'top', color: '#000', - font: { size: 11, weight: 'bold' } + font: { size: 11, weight: 'bold' }, + formatter: (value) => 'S/ ' + new Intl.NumberFormat('es-PE').format(value) } }, scales: { y: { beginAtZero: true, - grid: { color: 'rgba(0,0,0,0.05)' } + grid: { color: 'rgba(0,0,0,0.05)' }, + title: { display: true, text: 'Monto Total (Soles)' } }, x: { grid: { display: false }, @@ -1148,8 +1193,8 @@ include 'layout_header.php'; data: { labels: , datasets: [{ - label: 'Unidades', - data: , + label: 'Monto Total (S/)', + data: , backgroundColor: '#0dcaf0', borderRadius: 5, barPercentage: 0.7 @@ -1165,13 +1210,15 @@ include 'layout_header.php'; anchor: 'end', align: 'top', color: '#000', - font: { size: 11, weight: 'bold' } + font: { size: 11, weight: 'bold' }, + formatter: (value) => 'S/ ' + new Intl.NumberFormat('es-PE').format(value) } }, scales: { y: { beginAtZero: true, - grid: { color: 'rgba(0,0,0,0.05)' } + grid: { color: 'rgba(0,0,0,0.05)' }, + title: { display: true, text: 'Monto Total (Soles)' } }, x: { grid: { display: false }, @@ -1348,8 +1395,8 @@ include 'layout_header.php'; data: { labels: , datasets: [{ - label: 'Número de Pedidos', - data: , + label: 'Recaudo Total (S/)', + data: , backgroundColor: '#198754', borderRadius: 5, }] @@ -1364,11 +1411,12 @@ include 'layout_header.php'; anchor: 'end', align: 'right', color: '#000', - font: { weight: 'bold' } + font: { weight: 'bold' }, + formatter: (value) => 'S/ ' + new Intl.NumberFormat('es-PE').format(value) } }, scales: { - x: { beginAtZero: true, title: { display: true, text: 'Cantidad de Pedidos' } }, + x: { beginAtZero: true, title: { display: true, text: 'Recaudo (Soles)' } }, y: { ticks: { font: { size: 10 } } } } }