From 5e58b14eba1fcb886b8bb2ed7e6a7efdf20af87a Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Thu, 9 Apr 2026 16:38:03 -0500 Subject: [PATCH] reportes --- api/lab/get_reporte_pagos.php | 127 ++++++++++++++ lab_reportes.php | 311 ++++++++++++++++++++++++++++++++++ 2 files changed, 438 insertions(+) create mode 100644 api/lab/get_reporte_pagos.php diff --git a/api/lab/get_reporte_pagos.php b/api/lab/get_reporte_pagos.php new file mode 100644 index 0000000..ad2a141 --- /dev/null +++ b/api/lab/get_reporte_pagos.php @@ -0,0 +1,127 @@ + 12) $mes = (int)date('n'); + $wheres[] = 'YEAR(d.fecha_programada) = ?'; + $params[] = $anio; + $wheres[] = 'MONTH(d.fecha_programada) = ?'; + $params[] = $mes; + break; + + case 'rango': + $desde = $_GET['desde'] ?? date('Y-m-01'); + $hasta = $_GET['hasta'] ?? date('Y-m-d'); + if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $desde)) $desde = date('Y-m-01'); + if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $hasta)) $hasta = date('Y-m-d'); + $wheres[] = 'DATE(d.fecha_programada) BETWEEN ? AND ?'; + $params[] = $desde; + $params[] = $hasta; + break; + + default: // dia + $fecha = $_GET['fecha'] ?? date('Y-m-d'); + if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $fecha)) $fecha = date('Y-m-d'); + $wheres[] = 'DATE(d.fecha_programada) = ?'; + $params[] = $fecha; + break; +} + +// Filtro por enfermera +$enfermeraId = null; +if (!empty($_GET['enfermera_id']) && ctype_digit($_GET['enfermera_id'])) { + $enfermeraId = (int)$_GET['enfermera_id']; + $wheres[] = 'a.enfermera_id = ?'; + $params[] = $enfermeraId; +} + +$where = $wheres ? 'WHERE ' . implode(' AND ', $wheres) : ''; + +$filas = $db->fetchAll( + "SELECT + d.id, + d.fecha_programada, + d.pago_fecha, + p.nombre_completo AS paciente, + p.numero_documento, + COALESCE(e.nombre_completo,'Sin asignar') AS enfermera, + d.tipo_cliente, + COALESCE(d.seguro_nombre,'') AS seguro_nombre, + d.estado AS dom_estado, + COALESCE(d.valor_domicilio, 0) AS valor_domicilio, + d.pago_estado, + COALESCE(d.pago_modo,'') AS pago_modo, + COALESCE(d.pago_monto, 0) AS pago_monto, + COALESCE(d.pago_notas,'') AS pago_notas + FROM lab_domicilios d + JOIN lab_pacientes p ON p.id = d.paciente_id + LEFT JOIN lab_asignaciones a ON a.domicilio_id = d.id AND a.estado NOT IN ('liberada') + LEFT JOIN lab_enfermeras e ON e.id = a.enfermera_id + $where + ORDER BY d.fecha_programada ASC, d.id ASC", + $params +); + +// Resumen financiero +$resumen = [ + 'total' => count($filas), + 'pagados' => 0, + 'pendientes' => 0, + 'exentos' => 0, + 'monto_total' => 0.0, + 'por_modo' => [], +]; + +foreach ($filas as $f) { + $est = $f['pago_estado'] ?? 'pendiente'; + if ($est === 'pagado') { + $resumen['pagados']++; + $resumen['monto_total'] += (float)$f['pago_monto']; + $key = $f['pago_modo'] ?: 'sin_registrar'; + $resumen['por_modo'][$key] = ($resumen['por_modo'][$key] ?? 0.0) + (float)$f['pago_monto']; + } elseif ($est === 'exento') { + $resumen['exentos']++; + } else { + $resumen['pendientes']++; + } +} + +// Lista de enfermeras para poblar el selector +$enfermeras = $db->fetchAll( + "SELECT id, nombre_completo FROM lab_enfermeras WHERE is_active = 1 ORDER BY nombre_completo" +); + +echo json_encode([ + 'success' => true, + 'filas' => $filas, + 'resumen' => $resumen, + 'enfermeras' => $enfermeras, +], JSON_UNESCAPED_UNICODE); diff --git a/lab_reportes.php b/lab_reportes.php index ddacea2..3010497 100644 --- a/lab_reportes.php +++ b/lab_reportes.php @@ -136,6 +136,67 @@ if ($tipo) { $headers = ['ID','Nombre','Tipo Doc.','Documento','Teléfono','Email','EPS','Ciudad','Barrio','Activo','Total Órdenes','Registrado']; break; + case 'pagos': + $pModo = in_array($_GET['modo'] ?? '', ['dia','mes','rango']) ? $_GET['modo'] : 'dia'; + $pWheres = []; + $pParams = []; + switch ($pModo) { + case 'mes': + $pAnio = isset($_GET['anio']) && ctype_digit($_GET['anio']) ? (int)$_GET['anio'] : (int)date('Y'); + $pMes = isset($_GET['mes']) && ctype_digit($_GET['mes']) ? (int)$_GET['mes'] : (int)date('n'); + if ($pMes < 1 || $pMes > 12) $pMes = (int)date('n'); + $pWheres[] = 'YEAR(d.fecha_programada) = ?'; $pParams[] = $pAnio; + $pWheres[] = 'MONTH(d.fecha_programada) = ?'; $pParams[] = $pMes; + $rangoNombre = sprintf('%04d-%02d', $pAnio, $pMes); + break; + case 'rango': + $pDesde = $_GET['desde'] ?? date('Y-m-01'); + $pHasta = $_GET['hasta'] ?? date('Y-m-d'); + if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $pDesde)) $pDesde = date('Y-m-01'); + if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $pHasta)) $pHasta = date('Y-m-d'); + $pWheres[] = 'DATE(d.fecha_programada) BETWEEN ? AND ?'; + $pParams[] = $pDesde; $pParams[] = $pHasta; + $rangoNombre = "{$pDesde}_{$pHasta}"; + break; + default: // dia + $pFecha = $_GET['fecha'] ?? date('Y-m-d'); + if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $pFecha)) $pFecha = date('Y-m-d'); + $pWheres[] = 'DATE(d.fecha_programada) = ?'; + $pParams[] = $pFecha; + $rangoNombre = $pFecha; + } + if (!empty($_GET['enfermera_id']) && ctype_digit($_GET['enfermera_id'])) { + $pWheres[] = 'a.enfermera_id = ?'; + $pParams[] = (int)$_GET['enfermera_id']; + } + $pWhere = $pWheres ? 'WHERE ' . implode(' AND ', $pWheres) : ''; + $rows = $db->fetchAll( + "SELECT d.id, d.fecha_programada, d.pago_fecha, + p.nombre_completo AS paciente, p.numero_documento, + COALESCE(e.nombre_completo,'Sin asignar') AS enfermera, + d.tipo_cliente, COALESCE(d.seguro_nombre,'') AS seguro, + d.estado AS dom_estado, + COALESCE(d.valor_domicilio,0) AS valor_domicilio, + COALESCE(d.pago_estado,'pendiente') AS pago_estado, + COALESCE(d.pago_modo,'') AS pago_modo, + COALESCE(d.pago_monto,0) AS pago_monto, + COALESCE(d.pago_notas,'') AS pago_notas + FROM lab_domicilios d + JOIN lab_pacientes p ON p.id = d.paciente_id + LEFT JOIN lab_asignaciones a ON a.domicilio_id = d.id AND a.estado NOT IN ('liberada') + LEFT JOIN lab_enfermeras e ON e.id = a.enfermera_id + $pWhere + ORDER BY d.fecha_programada ASC, d.id ASC", + $pParams + ); + $filename = "reporte_pagos_{$rangoNombre}.csv"; + $headers = [ + 'ID','Fecha programada','Fecha pago','Paciente','Documento', + 'Enfermero/a','Tipo cliente','Seguro','Estado domicilio', + 'Valor domicilio','Estado pago','Modo pago','Monto recibido','Notas pago', + ]; + break; + default: http_response_code(400); exit('Tipo de exportación no válido'); @@ -244,6 +305,100 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user'][' + + + +
Sin domicilios para los filtros seleccionados.
'; + return; + } + + const PAGO_BADGE = { pagado:'success', pendiente:'warning', exento:'secondary' }; + const DOM_BADGE = { completado:'success', cancelado:'danger', programado:'secondary', + confirmado:'info', en_camino:'primary', reprogramado:'dark' }; + + wrap.innerHTML = ` +| # | +Fecha prog. | +Paciente | +Documento | +Enfermero/a | +Tipo cliente | +Valor domicilio | +Estado pago | +Modo pago | +Monto recibido | +Fecha pago | +Estado domicilio | +Notas pago | +
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ${f.id} | +${esc(f.fecha_programada?.slice(0,10) || '—')} | +${esc(f.paciente)} | +${esc(f.numero_documento || '—')} | +${esc(f.enfermera)} | +${cliente} | +${fmtMoney(f.valor_domicilio)} | ++ ${esc(pagoEst)} + | +${esc(f.pago_modo) || '—'} | ++ ${pagoEst === 'pagado' ? fmtMoney(f.pago_monto) : '—'} + | +${f.pago_fecha ? esc(f.pago_fecha.slice(0,16)) : '—'} | ++ ${esc(domEst)} + | +${esc(f.pago_notas) || ''} | +
| Total | +${fmtMoney(d.filas.reduce((s,f) => s + parseFloat(f.valor_domicilio||0), 0))} | ++ | ${fmtMoney(rs.monto_total)} | ++ | ||||||||