= DATE_SUB(CURDATE(), INTERVAL 7 DAY)"; $label_period = "Últimos 7 días"; break; case '15': $date_condition = "DATE(p.created_at) >= DATE_SUB(CURDATE(), INTERVAL 15 DAY)"; $label_period = "Últimos 15 días"; break; case '30': $date_condition = "DATE(p.created_at) >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)"; $label_period = "Últimos 30 días"; break; case 'month': $date_condition = "MONTH(p.created_at) = MONTH(CURDATE()) AND YEAR(p.created_at) = YEAR(CURDATE())"; $label_period = "Este Mes"; break; case 'last_month': $date_condition = "MONTH(p.created_at) = MONTH(DATE_SUB(CURDATE(), INTERVAL 1 MONTH)) AND YEAR(p.created_at) = YEAR(DATE_SUB(CURDATE(), INTERVAL 1 MONTH))"; $label_period = "Mes Anterior"; break; case '3_months': $date_condition = "DATE(p.created_at) >= DATE_SUB(CURDATE(), INTERVAL 3 MONTH)"; $label_period = "Últimos 3 Meses"; break; case '6_months': $date_condition = "DATE(p.created_at) >= DATE_SUB(CURDATE(), INTERVAL 6 MONTH)"; $label_period = "Últimos 6 Meses"; break; case 'year': $date_condition = "DATE(p.created_at) >= DATE_SUB(CURDATE(), INTERVAL 1 YEAR)"; $label_period = "Último Año"; break; default: $date_condition = "DATE(p.created_at) >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)"; $label_period = "Últimos 7 días"; $period = '7'; } } // 1. Estadísticas del periodo seleccionado $stmtStats = $db->query("SELECT COUNT(*) as total_pedidos, SUM(monto_total) as total_dinero FROM pedidos p WHERE $date_condition AND estado != 'RETORNADO'"); $statsPeriodo = $stmtStats->fetch(PDO::FETCH_ASSOC); // 2. Pedidos Pendientes (Global, no depende del filtro de fecha usualmente, pero lo mantendremos así) $stmtPendientes = $db->query("SELECT COUNT(*) FROM pedidos WHERE estado = 'ROTULADO 📦'"); $pendientes = $stmtPendientes->fetchColumn(); // 3. Recaudo Esperado (Global) $stmtRecaudo = $db->query("SELECT SUM(monto_debe) FROM pedidos WHERE estado IN ('EN TRANSITO 🚛', 'EN DESTINO 🏬', 'RUTA_CONTRAENTREGA') AND (estado_pago != 'Pagado' OR estado_pago IS NULL)"); $recaudoEsperado = $stmtRecaudo->fetchColumn() ?: 0; // 4. Stock Crítico (Global) $stmtStock = $db->query("SELECT COUNT(*) FROM (SELECT product_id, SUM(quantity) as total_stock FROM stock_sedes GROUP BY product_id HAVING total_stock <= 5) as critico"); $stockCritico = $stmtStock->fetchColumn() ?: 0; // 5. Datos para Gráfico de Ventas (Ajustado al periodo) $ventasTendencia = []; if ($period === 'today' || $period === 'yesterday') { // Si es hoy o ayer, mostrar por horas $stmt = $db->query("SELECT HOUR(p.created_at) as hora, COUNT(*) as cant, SUM(monto_total) as monto FROM pedidos p WHERE $date_condition AND estado != 'RETORNADO' GROUP BY HOUR(p.created_at) ORDER BY hora ASC"); $res = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($res as $r) { $ventasTendencia[] = ['fecha' => $r['hora'] . ':00', 'cantidad' => $r['cant'], 'monto' => $r['monto']]; } } elseif ($period === 'year') { // Si es un año, mostrar por meses $stmt = $db->query("SELECT DATE_FORMAT(p.created_at, '%Y-%m') as mes, COUNT(*) as cant, SUM(monto_total) as monto FROM pedidos p WHERE $date_condition AND estado != 'RETORNADO' GROUP BY mes ORDER BY mes ASC"); $res = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($res as $r) { $ventasTendencia[] = ['fecha' => date('M Y', strtotime($r['mes'] . '-01')), 'cantidad' => $r['cant'], 'monto' => $r['monto']]; } } else { // Mostrar por días $stmt = $db->query("SELECT DATE(p.created_at) as fecha, COUNT(*) as cant, SUM(monto_total) as monto FROM pedidos p WHERE $date_condition AND estado != 'RETORNADO' GROUP BY DATE(p.created_at) ORDER BY fecha ASC"); $res = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($res as $r) { $ventasTendencia[] = ['fecha' => date('d/m', strtotime($r['fecha'])), 'cantidad' => $r['cant'], 'monto' => $r['monto']]; } } // 6. Estados de Pedidos (Ajustado al periodo) $stmtEstados = $db->query("SELECT estado, COUNT(*) as total FROM pedidos p WHERE $date_condition GROUP BY estado"); $estadosData = $stmtEstados->fetchAll(PDO::FETCH_ASSOC); // 7. Top Productos (Ajustado al periodo) - TOTAL $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 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 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) $stmtAsesores = $db->query("SELECT u.nombre_asesor, COUNT(p.id) as total_pedidos, COALESCE(SUM(p.monto_total), 0) as total_monto, COUNT(CASE WHEN p.estado = 'COMPLETADO ✅' THEN 1 END) as completados FROM users u LEFT JOIN pedidos p ON u.id = p.asesor_id AND $date_condition AND p.estado != 'RETORNADO' WHERE u.role IN ('Asesor', 'admin', 'Administrador') GROUP BY u.id HAVING total_pedidos > 0 ORDER BY total_monto DESC"); $ventasAsesores = $stmtAsesores->fetchAll(PDO::FETCH_ASSOC); // 9. Comparativa Mensual (Se mantiene global para contexto) $mesActual = date('Y-m'); $mesPasado = date('Y-m', strtotime('first day of last month')); $stmtMesActual = $db->prepare("SELECT SUM(monto_total) as monto FROM pedidos p WHERE DATE_FORMAT(p.created_at, '%Y-%m') = ? AND estado != 'RETORNADO'"); $stmtMesActual->execute([$mesActual]); $montoMesActual = $stmtMesActual->fetchColumn() ?: 0; $stmtMesPasado = $db->prepare("SELECT SUM(monto_total) as monto FROM pedidos p WHERE DATE_FORMAT(p.created_at, '%Y-%m') = ? AND estado != 'RETORNADO'"); $stmtMesPasado->execute([$mesPasado]); $montoMesPasado = $stmtMesPasado->fetchColumn() ?: 0; $crecimientoMensual = $montoMesPasado > 0 ? (($montoMesActual - $montoMesPasado) / $montoMesPasado) * 100 : 0; // 10. Eficiencia Logística (Ajustado al periodo) $stmtTiempo = $db->query("SELECT AVG(TIMESTAMPDIFF(HOUR, p.created_at, fecha_completado)) / 24 as promedio_dias FROM pedidos p WHERE $date_condition AND estado = 'COMPLETADO ✅' AND fecha_completado IS NOT NULL"); $tiempoPromedio = $stmtTiempo->fetchColumn() ?: 0; $stmtRetorno = $db->query("SELECT (COUNT(CASE WHEN estado = 'RETORNADO' THEN 1 END) * 100.0 / NULLIF(COUNT(*), 0)) as tasa_retorno FROM pedidos p WHERE $date_condition"); $tasaRetorno = $stmtRetorno->fetchColumn() ?: 0; // 11. Utilidad Total Estimada (Ajustado al periodo) $stmtUtilidad = $db->query(" SELECT SUM(p.monto_total - (COALESCE(pr.costo, 0) * p.cantidad)) as utilidad_total FROM pedidos p LEFT JOIN products pr ON p.producto = pr.nombre WHERE $date_condition AND p.estado != 'RETORNADO' "); $utilidadTotal = $stmtUtilidad->fetchColumn() ?: 0; // 12. Datos Detallados por Canal (Provincia vs Contraentrega) $stmtDetalleCanal = $db->query("SELECT CASE WHEN estado IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA', 'RETORNADO') THEN 'Contraentrega' ELSE 'Provincia' END as canal, estado, COUNT(*) as total, SUM(monto_total) as monto FROM pedidos p WHERE $date_condition GROUP BY canal, estado"); $detalleCanalRaw = $stmtDetalleCanal->fetchAll(PDO::FETCH_ASSOC); // 13. Top Productos Detallado (Para la tabla) - TOTAL $stmtTopDetalle = $db->query(" 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 producto ORDER BY monto_total DESC "); $topProductosDetalle = $stmtTopDetalle->fetchAll(PDO::FETCH_ASSOC); // 13b. Top Productos Detallado Contraentrega $stmtTopDetalleCE = $db->query(" 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 producto ORDER BY monto_total DESC "); $topProductosDetalleCE = $stmtTopDetalleCE->fetchAll(PDO::FETCH_ASSOC); // 13c. Top Productos Detallado Provincia $stmtTopDetalleProv = $db->query(" 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 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 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, COUNT(*) as total FROM pedidos p WHERE $date_condition AND estado IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA', 'RETORNADO') GROUP BY producto ORDER BY total DESC "); $prodRendimientoCE = $stmtProdRendimientoCE->fetchAll(PDO::FETCH_ASSOC); // 15. Rendimiento de Productos en Provincia $stmtProdRendimientoProv = $db->query(" SELECT 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, COUNT(*) as total FROM pedidos p WHERE $date_condition AND estado NOT IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA', 'RETORNADO') GROUP BY producto ORDER BY total DESC "); $prodRendimientoProv = $stmtProdRendimientoProv->fetchAll(PDO::FETCH_ASSOC); // 16. Top Upsells (Combinaciones de productos distintos) $stmtTopUpsell = $db->query(" 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, cantidad ORDER BY recaudo DESC "); $topUpsells = $stmtTopUpsell->fetchAll(PDO::FETCH_ASSOC); $canalesResumen = [ 'Provincia' => ['pedidos' => 0, 'monto' => 0, 'estados' => []], 'Contraentrega' => ['pedidos' => 0, 'monto' => 0, 'estados' => []] ]; foreach ($detalleCanalRaw as $row) { $canal = $row['canal']; $estado = $row['estado']; if ($estado != 'RETORNADO') { $canalesResumen[$canal]['pedidos'] += $row['total']; $canalesResumen[$canal]['monto'] += $row['monto']; } if (!isset($canalesResumen[$canal]['estados'][$estado])) { $canalesResumen[$canal]['estados'][$estado] = 0; } $canalesResumen[$canal]['estados'][$estado] += $row['total']; } $pageTitle = "Dashboard Principal"; include 'layout_header.php'; ?>
Mostrando datos de:
pedidos
Margen bruto del periodo
Por procesar
En ruta (Global)
Bajo stock
| Producto | Cant. | Monto Total |
|---|---|---|
| S/ |
| Producto | Cant. | Monto |
|---|---|---|
| S/ |
| Producto | Cant. | Monto |
|---|---|---|
| S/ |
No se encontraron pedidos con combinaciones de productos distintos en este periodo.
| Combinación de Productos | Pedidos | Recaudo |
|---|---|---|
| ' . htmlspecialchars($parts_combo[0]) . ' '; $displayName = $parts_combo[1]; } $parts = explode(', ', $displayName); foreach($parts as $index => $part) { echo '' . htmlspecialchars($part) . '' . ($index < count($parts)-1 ? ' ' : ''); } ?> | S/ |