only(['start', 'end', 'type', 'action', 'period', 'charts_only']); $input = array_merge(['action' => 'index', 'type' => 'api'], $query); $startDate = $input['start'] ?? date('Y-01-01'); $endDate = $input['end'] ?? date('Y-12-31'); $period = $input['period'] ?? null; $chartsOnly = $input['charts_only'] ?? false; // Cache key para diferentes tipos de peticiones $cacheKey = 'atencion_' . md5(serialize([ 'start' => $startDate, 'end' => $endDate, 'period' => $period, 'charts_only' => $chartsOnly ])); // Intentar obtener desde cache (2 minutos) if (Cache::has($cacheKey)) { return response()->json(Cache::get($cacheKey), 200) ->header('Content-Type', 'application/json'); } try { // Si solo necesitamos gráficas, hacer menos peticiones if ($chartsOnly) { $result = $this->getChartsData($startDate, $endDate); } else { $result = $this->getFullData($startDate, $endDate, $period); } // Cachear resultado por 2 minutos Cache::put($cacheKey, $result, 120); return response()->json($result, 200) ->header('Content-Type', 'application/json'); } catch (\Exception $e) { Log::error('Error en la consulta de atención', ['exception' => $e->getMessage()]); return response()->json(['error' => 'Error en la consulta de atención'], 500); } } private function getChartsData($startDate, $endDate) { $baseParams = [ 'start_date' => $startDate, 'end_date' => $endDate, 'type' => 'api', 'action' => 'index', ]; $baseUrl = 'https://apoyos.comalcalco.gob.mx/beneficiaries/stats-by-date-range'; // Solo hacer la petición principal para gráficas $response = Http::timeout(15)->get($baseUrl, $baseParams); if (!$response->successful()) { throw new \Exception('Error del servicio principal'); } return $response->json(); } private function getFullData($startDate, $endDate, $period) { $baseParams = [ 'start_date' => $startDate, 'end_date' => $endDate, 'type' => 'api', 'action' => 'index', ]; $urls = [ 'main' => 'https://apoyos.comalcalco.gob.mx/beneficiaries/stats-by-date-range', 'counts' => 'https://apoyos.comalcalco.gob.mx/beneficiaries/counts-by-date', 'dashboard' => 'https://apoyos.comalcalco.gob.mx/beneficiaries/dashboard/api', 'dashboard_servicio' => 'https://apoyos.comalcalco.gob.mx/beneficiaries/dashboard/api?type=servicio' ]; // Hacer peticiones en paralelo usando HTTP Pool $responses = Http::pool(fn($pool) => [ $pool->timeout(15)->get($urls['main'], $baseParams), $pool->timeout(15)->get($urls['counts'], [ 'start_date' => $startDate, 'end_date' => $endDate, ]), $pool->timeout(15)->get($urls['dashboard']), $pool->timeout(15)->get($urls['dashboard_servicio']) ]); $mainData = []; $countsAc = []; $dashboardData = []; $dashboardServicioData = []; // Procesar respuestas if ($responses[0]->successful()) { $mainData = $responses[0]->json(); } else { Log::error('Error en petición principal', ['status' => $responses[0]->status()]); } if ($responses[1]->successful()) { $countsAc = $responses[1]->json(); } else { Log::error('Error en petición counts', ['status' => $responses[1]->status()]); } if ($responses[2]->successful()) { $dashboardData = $responses[2]->json(); } else { Log::error('Error en petición dashboard', ['status' => $responses[2]->status()]); } if ($responses[3]->successful()) { $dashboardServicioData = $responses[3]->json(); } else { Log::error('Error en petición dashboard servicio', ['status' => $responses[3]->status()]); } // Combinar todos los resultados return array_merge( is_array($mainData) ? $mainData : [], [ 'counts' => $countsAc, 'dashboard' => $dashboardData, 'dashboard_servicio' => $dashboardServicioData, ] ); } public function exportExcel(Request $request) { try { // Obtener parámetros necesarios para la API $params = $request->only([ 'start_date', 'end_date', 'department' ]); // Validaciones básicas if (!isset($params['start_date']) || !isset($params['end_date'])) { return response()->json([ 'error' => 'Las fechas son requeridas' ], 400); } if (!isset($params['department']) || $params['department'] === '') { return response()->json([ 'error' => 'El departamento es requerido' ], 400); } // Validar que department sea 1 o 3 if (!in_array((int)$params['department'], [1, 3])) { return response()->json([ 'error' => 'El departamento debe ser Atención Ciudadana o DIF' ], 400); } $url = 'https://apoyos.comalcalco.gob.mx/api/beneficiaries/export-excel'; // Hacer la petición a la API externa $response = Http::withoutVerifying() ->timeout(60) ->get($url, $params); if (!$response->successful()) { Log::error('Error al exportar Excel', [ 'status' => $response->status(), 'body' => $response->body(), 'params' => $params ]); return response()->json([ 'error' => 'Error al generar el archivo Excel: ' . $response->body() ], $response->status()); } // Verificar que la respuesta sea realmente un Excel $contentType = $response->header('Content-Type'); if (!str_contains($contentType, 'spreadsheet') && !str_contains($contentType, 'excel') && !str_contains($contentType, 'octet-stream')) { Log::error('Respuesta no es un archivo Excel', [ 'url' => $url, 'params' => $params, 'status' => $response->status(), 'content_type' => $contentType, 'body_preview' => substr($response->body(), 0, 500) ]); return response()->json([ 'error' => 'La API externa no devolvió un archivo Excel válido. URL: ' . $url . ' | Status: ' . $response->status() ], 400); } // Nombre del departamento para el archivo $departmentName = $params['department'] == 1 ? 'AtencionCiudadana' : 'DIF'; // Retornar el archivo Excel directamente con headers correctos return response($response->body(), 200, [ 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'Content-Disposition' => 'attachment; filename="beneficiarios_' . $departmentName . '_' . $params['start_date'] . '_' . $params['end_date'] . '.xlsx"', 'Content-Length' => strlen($response->body()), 'Cache-Control' => 'no-cache, no-store, must-revalidate', 'Pragma' => 'no-cache', 'Expires' => '0' ]); } catch (\Exception $e) { Log::error('Error en exportExcel', [ 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString(), 'params' => $request->all() ]); return response()->json([ 'error' => 'Error interno del servidor: ' . $e->getMessage() ], 500); } } }