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, COALESCE(d.valor_copago, 0) AS valor_copago, 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 ); // Enriquecer con parcialidades de pago $domIds = array_column($filas, 'id'); $parciales = []; if ($domIds) { $in = implode(',', array_map('intval', $domIds)); $rows = $db->fetchAll( "SELECT domicilio_id, modo, monto, notas FROM lab_domicilio_pagos WHERE domicilio_id IN ($in) ORDER BY id ASC" ); foreach ($rows as $row) { $parciales[(int)$row['domicilio_id']][] = $row; } } foreach ($filas as &$f) { $f['pagos_detalle'] = $parciales[(int)$f['id']] ?? []; } unset($f); // Resumen financiero — sumar desde parcialidades cuando existen $resumen = [ 'total' => count($filas), 'pagados' => 0, 'pendientes' => 0, 'exentos' => 0, 'monto_total' => 0.0, 'total_valor_dom' => 0.0, // suma valor_domicilio esperado 'total_valor_copago' => 0.0, // suma valor_copago esperado 'por_modo' => [], ]; foreach ($filas as $f) { $est = $f['pago_estado'] ?? 'pendiente'; // Acumular valores esperados (siempre, no solo pagados) $resumen['total_valor_dom'] += (float)($f['valor_domicilio'] ?? 0); $resumen['total_valor_copago'] += (float)($f['valor_copago'] ?? 0); if ($est === 'pagado') { $resumen['pagados']++; if (!empty($f['pagos_detalle'])) { // Sumar desde parcialidades foreach ($f['pagos_detalle'] as $p) { $monto = (float)$p['monto']; $key = $p['modo'] ?: 'sin_registrar'; $resumen['monto_total'] += $monto; $resumen['por_modo'][$key] = ($resumen['por_modo'][$key] ?? 0.0) + $monto; } } else { // Fallback registro legacy $monto = (float)$f['pago_monto']; $key = $f['pago_modo'] ?: 'sin_registrar'; $resumen['monto_total'] += $monto; $resumen['por_modo'][$key] = ($resumen['por_modo'][$key] ?? 0.0) + $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);