From 3a19f08bf8c86a25157e2b6eb6322622f4ee4ad4 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Tue, 21 Apr 2026 21:13:35 -0500 Subject: [PATCH] up --- modules/turnero/api/export_historial.php | 152 +++++++ modules/turnero/api/get_historial.php | 165 +++++++ modules/turnero/module.php | 1 + modules/turnero/views/historial.php | 552 +++++++++++++++++++++++ run_migration_005.php | 46 ++ 5 files changed, 916 insertions(+) create mode 100644 modules/turnero/api/export_historial.php create mode 100644 modules/turnero/api/get_historial.php create mode 100644 modules/turnero/views/historial.php create mode 100644 run_migration_005.php diff --git a/modules/turnero/api/export_historial.php b/modules/turnero/api/export_historial.php new file mode 100644 index 0000000..4031c84 --- /dev/null +++ b/modules/turnero/api/export_historial.php @@ -0,0 +1,152 @@ + $fechaHasta) $fechaDesde = $fechaHasta; + +$estadoFiltro = trim($_GET['estado'] ?? ''); +$lugarId = (int)($_GET['lugar_id'] ?? 0); +$prioridadId = (int)($_GET['prioridad_id'] ?? 0); +$q = trim($_GET['q'] ?? ''); + +// ── WHERE ───────────────────────────────────────────────────── +$where = ['DATE(ses.fecha) BETWEEN ? AND ?']; +$binds = [$fechaDesde, $fechaHasta]; + +$estadosValidos = ['espera','en_recepcion','en_espera_lugar','en_servicio','finalizado','ausente','cancelado']; +if ($estadoFiltro && in_array($estadoFiltro, $estadosValidos, true)) { + $where[] = 't.estado = ?'; + $binds[] = $estadoFiltro; +} +if ($lugarId > 0) { + $where[] = 't.lugar_destino_id = ?'; + $binds[] = $lugarId; +} +if ($prioridadId > 0) { + $where[] = 't.prioridad_id = ?'; + $binds[] = $prioridadId; +} +if ($q !== '') { + $where[] = '(t.codigo LIKE ? OR t.paciente_nombre LIKE ? OR pac.nombre_completo LIKE ?)'; + $like = '%' . $q . '%'; + $binds[] = $like; + $binds[] = $like; + $binds[] = $like; +} + +$whereStr = 'WHERE ' . implode(' AND ', $where); + +// ── Consulta ────────────────────────────────────────────────── +$sql = " + SELECT + ses.fecha AS fecha_sesion, + t.codigo, + t.numero, + p.codigo AS prioridad, + p.nombre AS prioridad_nombre, + COALESCE(pac.nombre_completo, t.paciente_nombre) AS paciente, + pac.numero_documento, + pac.tipo_documento, + t.paciente_cel AS celular, + l.nombre AS lugar, + t.estado, + t.creado_at, + t.llamado_recepcion_at, + t.inicio_recepcion_at, + t.fin_recepcion_at, + t.llamado_lugar_at, + t.inicio_lugar_at, + t.fin_lugar_at, + ROUND(TIMESTAMPDIFF(SECOND, t.creado_at, + COALESCE(t.inicio_recepcion_at, t.fin_recepcion_at)) / 60.0, 1) AS espera_recepcion_min, + ROUND(TIMESTAMPDIFF(SECOND, t.inicio_lugar_at, + COALESCE(t.fin_lugar_at, NOW())) / 60.0, 1) AS servicio_lugar_min, + sol.total_cobrado, + sol.metodo_pago + FROM turnero_turnos t + JOIN turnero_sesiones ses ON ses.id = t.sesion_id + JOIN turnero_prioridades p ON p.id = t.prioridad_id + LEFT JOIN turnero_lugares l ON l.id = t.lugar_destino_id + LEFT JOIN turnero_solicitudes sol ON sol.turno_id = t.id + LEFT JOIN lab_pacientes pac ON pac.id = sol.paciente_id + $whereStr + ORDER BY t.creado_at ASC"; + +$stmt = $pdo->prepare($sql); +$stmt->execute($binds); +$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); + +// ── Nombre de archivo ───────────────────────────────────────── +$nombreArchivo = "historial_turnos_{$fechaDesde}_a_{$fechaHasta}.csv"; + +// ── Output ──────────────────────────────────────────────────── +// Limpiar cualquier output previo antes de los headers +ob_clean(); + +header('Content-Type: text/csv; charset=utf-8'); +header('Content-Disposition: attachment; filename="' . $nombreArchivo . '"'); +header('Cache-Control: no-cache, no-store, must-revalidate'); +header('Pragma: no-cache'); +header('Expires: 0'); + +$out = fopen('php://output', 'w'); +echo "\xEF\xBB\xBF"; // BOM UTF-8 para Excel + +// Encabezados +$headers = [ + 'Fecha', 'Código', 'Número', 'Prioridad', 'Prioridad nombre', + 'Paciente', 'Documento', 'Tipo doc.', 'Celular', + 'Lugar', 'Estado', + 'Creado', 'Llamado recepción', 'Inicio recepción', 'Fin recepción', + 'Llamado lugar', 'Inicio lugar', 'Fin lugar', + 'Espera recepción (min)', 'Servicio lugar (min)', + 'Total cobrado', 'Método pago', +]; +fputcsv($out, $headers, ',', '"'); + +$fechaCols = [ + 'creado_at','llamado_recepcion_at','inicio_recepcion_at','fin_recepcion_at', + 'llamado_lugar_at','inicio_lugar_at','fin_lugar_at', +]; +$fields = [ + 'fecha_sesion', 'codigo', 'numero', 'prioridad', 'prioridad_nombre', + 'paciente', 'numero_documento', 'tipo_documento', 'celular', + 'lugar', 'estado', + 'creado_at', 'llamado_recepcion_at', 'inicio_recepcion_at', 'fin_recepcion_at', + 'llamado_lugar_at', 'inicio_lugar_at', 'fin_lugar_at', + 'espera_recepcion_min', 'servicio_lugar_min', + 'total_cobrado', 'metodo_pago', +]; + +foreach ($rows as $row) { + $line = []; + foreach ($fields as $f) { + $v = $row[$f] ?? ''; + if ($v && in_array($f, $fechaCols, true)) { + $v = date('d/m/Y H:i:s', strtotime($v)); + } + $line[] = $v; + } + fputcsv($out, $line, ',', '"'); +} + +fclose($out); +exit; diff --git a/modules/turnero/api/get_historial.php b/modules/turnero/api/get_historial.php new file mode 100644 index 0000000..b33e391 --- /dev/null +++ b/modules/turnero/api/get_historial.php @@ -0,0 +1,165 @@ + $fechaHasta) $fechaDesde = $fechaHasta; + +$estadoFiltro = trim($_GET['estado'] ?? ''); +$lugarId = (int)($_GET['lugar_id'] ?? 0); +$prioridadId = (int)($_GET['prioridad_id'] ?? 0); +$q = trim($_GET['q'] ?? ''); + +$perPage = min(200, max(10, (int)($_GET['per_page'] ?? 50))); +$page = max(1, (int)($_GET['page'] ?? 1)); +$offset = ($page - 1) * $perPage; + +// ── Base WHERE ─────────────────────────────────────────────── +// Unimos turnos con sesiones para filtrar por fecha de sesión +$where = ['DATE(s.fecha) BETWEEN ? AND ?']; +$binds = [$fechaDesde, $fechaHasta]; + +$estadosValidos = ['espera','en_recepcion','en_espera_lugar','en_servicio','finalizado','ausente','cancelado']; +if ($estadoFiltro && in_array($estadoFiltro, $estadosValidos, true)) { + $where[] = 't.estado = ?'; + $binds[] = $estadoFiltro; +} +if ($lugarId > 0) { + $where[] = 't.lugar_destino_id = ?'; + $binds[] = $lugarId; +} +if ($prioridadId > 0) { + $where[] = 't.prioridad_id = ?'; + $binds[] = $prioridadId; +} +if ($q !== '') { + $where[] = '(t.codigo LIKE ? OR t.paciente_nombre LIKE ? OR s2.nombre_completo LIKE ?)'; + $like = '%' . $q . '%'; + $binds[] = $like; + $binds[] = $like; + $binds[] = $like; +} + +$whereStr = 'WHERE ' . implode(' AND ', $where); + +// ── Conteo total ────────────────────────────────────────────── +$sqlCount = " + SELECT COUNT(*) AS total + FROM turnero_turnos t + JOIN turnero_sesiones s ON s.id = t.sesion_id + LEFT JOIN turnero_solicitudes ts2 ON ts2.turno_id = t.id + LEFT JOIN lab_pacientes s2 ON s2.id = ts2.paciente_id + $whereStr"; + +$stmtCount = $pdo->prepare($sqlCount); +$stmtCount->execute($binds); +$totalRows = (int)$stmtCount->fetchColumn(); +$totalPages = max(1, (int)ceil($totalRows / $perPage)); +if ($page > $totalPages) $page = $totalPages; +$offset = ($page - 1) * $perPage; + +// ── Lista paginada ──────────────────────────────────────────── +$sqlTurnos = " + SELECT + t.id, + t.codigo, + t.numero, + t.estado, + t.paciente_nombre, + t.paciente_cel, + t.creado_at, + t.inicio_recepcion_at, + t.fin_recepcion_at, + t.inicio_lugar_at, + t.fin_lugar_at, + s.fecha AS fecha_sesion, + p.codigo AS prioridad_codigo, + p.nombre AS prioridad_nombre, + p.color AS prioridad_color, + l.nombre AS lugar_nombre, + s2.nombre_completo AS paciente_bd, + ROUND(TIMESTAMPDIFF(SECOND, t.creado_at, + COALESCE(t.inicio_recepcion_at, t.fin_recepcion_at)) / 60.0, 1) + AS espera_min, + ROUND(TIMESTAMPDIFF(SECOND, t.inicio_lugar_at, + COALESCE(t.fin_lugar_at, NOW())) / 60.0, 1) + AS servicio_min + FROM turnero_turnos t + JOIN turnero_sesiones s ON s.id = t.sesion_id + JOIN turnero_prioridades p ON p.id = t.prioridad_id + LEFT JOIN turnero_lugares l ON l.id = t.lugar_destino_id + LEFT JOIN turnero_solicitudes ts2 ON ts2.turno_id = t.id + LEFT JOIN lab_pacientes s2 ON s2.id = ts2.paciente_id + $whereStr + ORDER BY t.creado_at DESC + LIMIT ? OFFSET ?"; + +$bindsPage = array_merge($binds, [$perPage, $offset]); +$stmtTurnos = $pdo->prepare($sqlTurnos); +$stmtTurnos->execute($bindsPage); +$turnos = $stmtTurnos->fetchAll(PDO::FETCH_ASSOC); + +// ── Resumen por estado (del rango filtrado) ─────────────────── +$sqlRes = " + SELECT t.estado, COUNT(*) AS cnt + FROM turnero_turnos t + JOIN turnero_sesiones s ON s.id = t.sesion_id + LEFT JOIN turnero_solicitudes ts2 ON ts2.turno_id = t.id + LEFT JOIN lab_pacientes s2 ON s2.id = ts2.paciente_id + $whereStr + GROUP BY t.estado"; +$stmtRes = $pdo->prepare($sqlRes); +$stmtRes->execute($binds); +$resumenEstados = []; +foreach ($stmtRes->fetchAll(PDO::FETCH_ASSOC) as $r) { + $resumenEstados[$r['estado']] = (int)$r['cnt']; +} + +// ── Catálogos para los selectores (si pide con ?meta=1) ────── +$meta = []; +if (!empty($_GET['meta'])) { + $meta['lugares'] = $pdo->query( + "SELECT id, nombre FROM turnero_lugares WHERE activo=1 ORDER BY sort_order ASC, nombre ASC" + )->fetchAll(PDO::FETCH_ASSOC); + + $meta['prioridades'] = $pdo->query( + "SELECT id, nombre, codigo, color FROM turnero_prioridades ORDER BY orden_peso ASC" + )->fetchAll(PDO::FETCH_ASSOC); +} + +jsonOk([ + 'fecha_desde' => $fechaDesde, + 'fecha_hasta' => $fechaHasta, + 'total' => $totalRows, + 'page' => $page, + 'per_page' => $perPage, + 'total_pages' => $totalPages, + 'resumen_estados'=> $resumenEstados, + 'turnos' => $turnos, + 'meta' => $meta, +]); diff --git a/modules/turnero/module.php b/modules/turnero/module.php index 1026300..a6b9994 100644 --- a/modules/turnero/module.php +++ b/modules/turnero/module.php @@ -7,6 +7,7 @@ // ── Links estáticos base ────────────────────────────────────── $_trLinks = [ ['name' => 'Dashboard', 'icon' => 'fas fa-tachometer-alt', 'route' => '/erp.php?m=turnero&v=dashboard'], + ['name' => 'Historial', 'icon' => 'fas fa-history', 'route' => '/erp.php?m=turnero&v=historial'], ['name' => 'Configuración', 'icon' => 'fas fa-sliders-h', 'route' => '/erp.php?m=turnero&v=configuracion'], ['name' => 'Kiosko', 'icon' => 'fas fa-desktop', 'route' => '/erp.php?m=turnero&v=kiosko'], ['name' => 'Pantalla TV Global', 'icon' => 'fas fa-th-large', 'route' => '/erp.php?m=turnero&v=display_global'], diff --git a/modules/turnero/views/historial.php b/modules/turnero/views/historial.php new file mode 100644 index 0000000..8dd70ab --- /dev/null +++ b/modules/turnero/views/historial.php @@ -0,0 +1,552 @@ + + + + + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + + + +
+ + +
+ + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
FechaCódigoPrioridadPacienteTeléfonoLugarEstadoEsperaServicioEntrada
Cargando…
+
+ + + +
+
+ + + + diff --git a/run_migration_005.php b/run_migration_005.php new file mode 100644 index 0000000..5f88178 --- /dev/null +++ b/run_migration_005.php @@ -0,0 +1,46 @@ +getConnection(); +$sqlFile = __DIR__ . '/migrations/005_registro_exams.sql'; +$sql = file_get_contents($sqlFile); + +// Separar sentencias (ignorar comentarios) +$statements = array_filter(array_map('trim', explode(';', $sql))); + +$results = []; +foreach ($statements as $stmt) { + if (empty($stmt) || preg_match('/^\s*--/', $stmt)) continue; + try { + $pdo->exec($stmt); + $results[] = ['ok' => true, 'sql' => substr(preg_replace('/\s+/', ' ', $stmt), 0, 120)]; + } catch (\PDOException $e) { + $results[] = ['ok' => false, 'sql' => substr(preg_replace('/\s+/', ' ', $stmt), 0, 120), 'error' => $e->getMessage()]; + } +} +?> +Migración 005 + + +

Migración 005 — Registro de Exámenes

+ + + + $r): ?> + + + + + + + + +
#EstadoSQLError
+
⚠️ Elimina este archivo del servidor después de ejecutarlo.
+Ir a Registro Exámenes +