sitio_web = config('sitioweb.sitio_web_erp_id', 0); } /** * Muestra el detalle de un vuelo específico. * * @param Request $request * @param int $id ID del vuelo * * @return \Illuminate\Http\JsonResponse * * Respuesta: * - 200: Objeto del vuelo * - 404: Vuelo no encontrado */ public function show(Request $request, int $id) { $lang = $request->get('lang', 'en'); $vuelo = $this->getVuelosData(collect([$id]), $lang)->first(); if (!$vuelo) { return response()->json( [ 'message' => 'Vuelo no encontrado', ], 404, ); } return response()->json($vuelo); } /** * Obtiene colección de vuelos visibles en la web. * * @return \Illuminate\Http\JsonResponse */ public function getVuelosCollection() { return $this->buildCollectionResponse(function ($query) { $query->where('visibilidad_pagina_web', 1); }); } /** * Obtiene colección de vuelos visibles en la home. * * @return \Illuminate\Http\JsonResponse */ public function getVuelosCollectionHome() { return $this->buildCollectionResponse(function ($query) { $query->where('visibilidad_pagina_web', 1)->where('show_flight_in_home_view', 0); }); } /** * Builder reutilizable para colecciones de vuelos. * * @param callable $callback Filtros dinámicos sobre la query base * * @return \Illuminate\Http\JsonResponse */ private function buildCollectionResponse(callable $callback) { $lang = app()->getLocale(); $query = DB::table('vuelos')->where('id_sitio_web', $this->sitio_web)->where('id_estatus', 1); $callback($query); $ids = $query->pluck('id_vuelo'); return response()->json([ 'vuelos' => $this->getVuelosData($ids, $lang)->values(), ]); } /** * Motor principal de transformación de vuelos. * * @param Collection $ids IDs de vuelos * @param string $lang Idioma actual * * @return Collection */ private function getVuelosData(Collection $ids, string $lang): Collection { if ($ids->isEmpty()) { return collect(); } $data = $this->fetchAllData($ids, $lang); return $ids->map(fn($id) => $this->transformVuelo($id, $data, $lang))->filter(); } /** * Obtiene todos los datos relacionados en bloque. * * @param Collection $ids * @param string $lang * * @return array */ private function fetchAllData(Collection $ids, string $lang): array { $vuelos = DB::table('vuelos')->whereIn('id_vuelo', $ids)->get()->keyBy('id_vuelo'); return [ 'vuelos' => $vuelos, 'vuelos_en' => $lang === 'en' ? DB::table('vuelos_usd')->whereIn('id_vuelo', $ids)->get()->keyBy('id_vuelo') : collect(), 'categorias' => DB::table('categorias_vuelos')->whereIn('id_categoria', $vuelos->pluck('id_categoria'))->get()->keyBy('id_categoria'), 'precios' => DB::table('vuelos_precios')->whereIn('id_vuelo', $ids)->where('id_estatus', 1)->get()->keyBy('id_vuelo'), 'imagenes' => DB::table('vuelos_imagenes_galeria')->whereIn('id_vuelo', $ids)->where('id_estatus', 1)->orderBy('orden')->get()->groupBy('id_vuelo'), 'incluye' => DB::table('vuelos_items_incluye')->whereIn('id_vuelo', $ids)->where('id_estatus', 1)->get()->groupBy('id_vuelo'), ]; } /** * Transforma un vuelo a su estructura final. * * @param int $id * @param array $data * @param string $lang * * @return array|null */ private function transformVuelo(int $id, array $data, string $lang): ?array { $vuelo = $data['vuelos'][$id] ?? null; if (!$vuelo) { return null; } $vuelo = $this->mergeIdioma($vuelo, $data['vuelos_en'][$id] ?? null, $lang); $vuelo = $this->normalizeVuelo($vuelo); $categoria = $data['categorias'][$vuelo->id_categoria] ?? null; return [ 'vuelo' => $vuelo, 'categoria' => [ 'nombre' => $lang === 'en' ? $categoria->nombre_categoria_usd ?? null : $categoria->nombre_categoria ?? null, ], 'precios' => $data['precios'][$id] ?? null, 'imagenes' => $data['imagenes'][$id] ?? collect(), 'incluye' => $data['incluye'][$id] ?? collect(), ]; } /** * Aplica traducción al vuelo si el idioma es inglés. * * @param mixed $vuelo * @param mixed $vuelo_en * @param string $lang * * @return mixed */ private function mergeIdioma($vuelo, $vuelo_en, string $lang) { if ($lang !== 'en' || !$vuelo_en) { return $vuelo; } $map = [ 'nombre_vuelo' => 'titulo_vuelo', 'descripcion_corta' => 'descripcion_corta', 'descripcion_larga' => 'descripcion_larga', 'json_incluye' => 'json_incluye', 'servicios_adicionales' => 'servicios_adicionales', 'precio_publico' => 'precio_usd', 'precio_especial' => 'precio_especial_usd', ]; foreach ($map as $target => $source) { if (isset($vuelo_en->$source)) { $vuelo->$target = $vuelo_en->$source; } } return $vuelo; } /** * Normaliza campos JSON del vuelo. * * @param mixed $vuelo * * @return mixed */ private function normalizeVuelo($vuelo) { $vuelo->json_incluye = $this->safeJsonDecode($vuelo->json_incluye); $vuelo->precios_adicionales = $this->safeJsonDecode($vuelo->precios_adicionales); return $vuelo; } /** * Decodifica JSON de forma segura. * * @param mixed $value * * @return array */ private function safeJsonDecode($value) { if (!$value || $value === 'null') { return []; } return json_decode($value, true) ?? []; } public static function obtenerServiciosAdicionales() { return DB::table('servicios_adicionales as sa') ->leftJoin('unidades as u', 'u.id_unidad', '=', 'sa.id_unidad') ->leftJoin('categorias as c', 'c.id_categoria', '=', 'sa.additional_service_category_id') ->select( DB::raw('COALESCE(c.nombre_categoria, "Sin categoría") as nombre_categoria'), DB::raw(" JSON_ARRAYAGG( JSON_OBJECT( 'id', sa.id_servicio_adicional, 'descripcion', TRIM(sa.descripcion), 'precio', CAST(sa.precio AS DECIMAL(10,2)), 'observaciones', TRIM(sa.observaciones), 'unidad', u.nombre_unidad, 'imagenes', COALESCE(( SELECT JSON_ARRAYAGG( JSON_UNQUOTE( JSON_EXTRACT(sag2.json_rutas_imagenes, '$[0]') ) ) FROM servicios_adicionales_galeria sag2 WHERE sag2.id_servicio_adicional = sa.id_servicio_adicional AND sag2.id_estatus = 1 ), JSON_ARRAY()) ) ) as servicios "), ) ->where('sa.id_estatus', 1) ->where('sa.visibilidad_web', 1) ->groupBy('nombre_categoria') ->orderBy('nombre_categoria') // ordena categorías ->get() ->map(function ($item) { return [ 'nombre_categoria' => $item->nombre_categoria, 'servicios' => json_decode($item->servicios, true), // 🔥 JSON → array real ]; }) ->values(); } /** * Busca el ID del vuelo a partir del slug (multilenguaje). * * @param string $slug * @param string $lang * @return int|null */ private function findVueloIdBySlug(string $slug, string $lang): ?int { // Buscar en tabla base (ES) $query = DB::table('vuelos')->where('id_sitio_web', $this->sitio_web)->where('id_estatus', 1); if ($lang === 'en') { // Buscar en tabla traducida return DB::table('vuelos_usd')->where('slug', $slug)->value('id_vuelo'); } return $query->where('slug', $slug)->value('id_vuelo'); } /** * Muestra el detalle de un vuelo por su enlace_permanente (slug permanente) * * Usa el idioma actual de la aplicación (sesión) * * @param Request $request * @param string $enlace_permanente * @return \Illuminate\Http\JsonResponse */ public function showByPermanentLink(Request $request, string $enlace_permanente) { $lang = app()->getLocale(); // 'es' o 'en' $id = $this->findVueloIdByPermanentLink($enlace_permanente, $lang); if (!$id) { return response()->json([ 'message' => $lang === 'en' ? 'Flight not found' : 'Vuelo no encontrado' ], 404); } $vuelo = $this->getVuelosData(collect([$id]), $lang)->first(); if (!$vuelo) { return response()->json([ 'message' => $lang === 'en' ? 'Flight not found' : 'Vuelo no encontrado' ], 404); } return response()->json($vuelo); } /** * Busca el ID del vuelo a partir del enlace permanente (slug canónico). * * @param string $enlace_permanente * @param string $lang * @return int|null */ private function findVueloIdByPermanentLink(string $enlace_permanente, string $lang): ?int { // Siempre buscar primero en la tabla base (canónica) $id = DB::table('vuelos') ->where('id_sitio_web', $this->sitio_web) ->where('id_estatus', 1) ->where('enlace_permanente', $enlace_permanente) ->value('id_vuelo'); if ($id) { return $id; } // Fallback opcional: si estás en inglés y existe en tabla traducida if ($lang === 'en') { return DB::table('vuelos_usd') ->where('enlace_permanente', $enlace_permanente) ->value('id_vuelo'); } return null; } public function getVuelosFoot() { } public static function cotizaVuelo($slug, Request $request) { //Insertar en NNewsletter \Log::info('Cotización recibida:', $request->all()); // return $request; DB::table('newsletter_skyballoons')->insert([ 'correo_electronico' => $request->email, 'origin_url' => 'https://' . DB::table('sitios_web')->where('id_sitio_web', 2)->value('url_web'), 'id_sitio_web' => 2, 'fecha_alta' => now(), ]); } }