vueloenglobo.mx/app/Http/Controllers/PaseAbordarController.php

612 lines
26 KiB
PHP

<?php
namespace App\Http\Controllers;
use Picqer\Barcode\BarcodeGeneratorPNG;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Carbon\Carbon;
class PaseAbordarController extends Controller
{
public function crearCotizacionDesdePagoExitoso($montoPagado = null, $metodoPago = 'card')
{
$reserva = session()->get('reserva_pendiente');
if (!$reserva) {
return response()->json(['error' => 'No hay reserva pendiente'], 400);
}
$id_cotizacion = $reserva['id_cotizacion'];
$folio = $reserva['folio'];
$datos = $reserva['datos'];
// Si no se pasó el monto pagado, usar el total de la compra
if ($montoPagado === null) {
$montoPagado = $datos['total_compra'];
}
DB::beginTransaction();
try {
// 1. Insertar en la tabla cotizaciones
$fecha_vuelo = isset($datos['fecha_vuelo'])
? Carbon::createFromFormat('m/d/Y', $datos['fecha_vuelo'])->format('Y-m-d')
: null;
// Construir el JSON de vuelos (exactamente como lo hacías con modelos)
$vuelos_field = [
[
'moneda' => 'MXN',
'precio_vendido_p_pax_vuelo' => $datos['precio_publico'],
'id_vuelo' => $datos['id_vuelo'],
'id_unidad' => $datos['id_unidad'],
'cantidades' => $datos['pasajeros'],
'precio_especial' => '0'
]
];
if (!empty($datos['num_pax_adicionales']) && $datos['num_pax_adicionales'] > 0) {
$vuelos_field[0]['pasajeros_adicionales'] = [
[
'moneda' => 'MXN',
'cantidades' => $datos['num_pax_adicionales'],
'id_unidad' => $datos['id_unidad_adicionales'],
'precio' => $datos['precio_adicional'],
'precio_especial' => $datos['precio_adicional']
]
];
}
DB::table('cotizaciones')->insert([
'id_sitio_web' => 6,
'cotizacion_abierta' => isset($datos['fecha_libre']) ? 1 : 0,
'folio' => $folio,
'nombre' => $datos['nombre_reserva'],
'apellidos' => $datos['apellido_reserva'],
'id_medio_contacto' => 12,
'id_genero' => 1,
'telefono' => $datos['tel_reserva'],
'iso_country_id_primary_phone' => $datos['Lada'],
'celular' => $datos['tel_reserva'],
'iso_country_id_secondary_phone' => $datos['Lada'],
'cp' => 0,
'mail' => $datos['email_reserva'],
'fecha_vuelo' => $fecha_vuelo,
'vuelos' => json_encode($vuelos_field),
'servicios_adicionales' => $datos['servicios_adicionales'],
'tipo_descuento' => null,
'descuento' => null,
'descuento_usd' => null,
'subtotal' => $datos['total_compra'],
'total' => $datos['total_compra'],
'total_con_iva' => $datos['total_compra'],
'subtotal_usd' => 0,
'total_usd' => 0,
'tipo_cargo' => 0,
'total_cargos' => 0,
'requiere_factura' => 0,
'observaciones' => 'checkout Globopuerto Teotihuacan',
'id_motivo' => 1,
'tipo_moneda' => 'MXN',
'pais_persona' => 484,
'estado_persona' => 1,
'id_user_alta' => 98,
'peso_kg' => 0,
'number_of_pax' => $this->getNumberOfPaxes(
$vuelos_field,
$vuelos_field[0]['pasajeros_adicionales'] ?? [],
$datos['id_vuelo']
),
'fecha_alta' => Carbon::now(),
]);
// 2. Insertar vuelos_cotizaciones (vuelo principal)
DB::table('vuelos_cotizaciones')->insert([
'id_vuelo' => $datos['id_vuelo'],
'id_unidad' => $datos['id_unidad'],
'cantidades' => $datos['pasajeros'],
'precio_vendido_p_pax_vuelo' => $datos['precio_publico'],
'precio_vendido_p_pax_usd' => 0,
'precio_especial' => $datos['precio_publico'],
'id_cotizacion' => $id_cotizacion,
'pasajero_adicional' => 0,
'id_estatus' => 1,
'id_user_alta' => 98,
'fecha_alta' => Carbon::now(),
]);
// 3. Insertar vuelos_cotizaciones adicionales (si existen)
if (!empty($datos['num_pax_adicionales']) && $datos['num_pax_adicionales'] > 0) {
DB::table('vuelos_cotizaciones')->insert([
'id_vuelo' => $datos['id_vuelo'],
'id_unidad' => $datos['id_unidad_adicionales'],
'cantidades' => $datos['num_pax_adicionales'],
'precio_vendido_p_pax_vuelo' => $datos['precio_adicional'],
'precio_vendido_p_pax_usd' => 0,
'precio_especial' => $datos['precio_adicional'],
'id_cotizacion' => $id_cotizacion,
'pasajero_adicional' => 1,
'id_estatus' => 1,
'id_user_alta' => 98,
'id_user_mod' => 98,
'fecha_alta' => Carbon::now(),
'fecha_mod' => Carbon::now(),
]);
}
// 4. Insertar servicios_adicionales_cotizaciones
if (!empty($datos['servicios_adicionales'])) {
$servicios = json_decode($datos['servicios_adicionales'], true);
foreach ($servicios as $servicio) {
DB::table('servicios_adicionales_cotizaciones')->insert([
'id_servicio_adicional' => $servicio['id_servicio'],
'cantidades' => $servicio['cantidad_solicitada'],
'id_unidad' => $servicio['id_unidad'],
'precio_vendido' => $servicio['precio'],
'precio_vendido_usd' => 0,
'id_cotizacion' => $id_cotizacion,
'id_estatus' => 1,
'id_user_alta' => 88,
'fecha_alta' => Carbon::now(),
]);
}
}
// 5. Insertar el pago llamando al procedimiento almacenado (usando DB::statement)
$params_pago = [
'hora_cita' => $datos['hora_cita'],
'id_cotizacion' => $id_cotizacion,
'foto_comprobante' => null,
'cantidad_pagada' => $montoPagado,
'cantidad_pagada_usd' => 0,
'pago_confirmado_default' => 1,
'fecha_pago' => Carbon::now()->toDateString(),
'observaciones' => 'Pago exitoso desde checkout',
'observaciones_logistica' => 'Pago exitoso',
'ultimos_digitos' => null,
'id_cuenta_bancaria' => 0,
'id_metodo_pago_cuenta_bancaria' => ($metodoPago == 'card' ? 6 : ($metodoPago == 'oxxo' ? 8 : 9)),
'id_banco' => ($metodoPago == 'card' ? 11 : ($metodoPago == 'oxxo' ? 12 : 2)),
'id_user_alta' => 98,
'fecha_alta' => Carbon::now(),
'crear_pase' => 1,
'id_lugar_cita' => $datos['id_lugar_cita'],
'generar_pase_ingles' => 0,
];
// Llamar al procedimiento almacenado sp_crear_pagos_reservacion
DB::statement('CALL sp_crear_pagos_reservacion(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [
$params_pago['hora_cita'],
$params_pago['id_cotizacion'],
$params_pago['foto_comprobante'],
$params_pago['cantidad_pagada'],
$params_pago['cantidad_pagada_usd'],
$params_pago['pago_confirmado_default'],
$params_pago['fecha_pago'],
$params_pago['observaciones'],
$params_pago['observaciones_logistica'],
$params_pago['ultimos_digitos'],
$params_pago['id_cuenta_bancaria'],
$params_pago['id_metodo_pago_cuenta_bancaria'],
$params_pago['id_banco'],
$params_pago['id_user_alta'],
$params_pago['fecha_alta'],
$params_pago['crear_pase'],
$params_pago['id_lugar_cita'],
$params_pago['generar_pase_ingles'],
]);
// 6. Enviar el pase (opcional, pero mantén la llamada a la API)
//$url_mail = "https://erp.skyballoons.mx/enviar-pase/6/" . $id_cotizacion;
//file_get_contents($url_mail); // o usar Http::get si prefieres
DB::commit();
// Limpiar la sesión para que no se pueda reutilizar
session()->forget('reserva_pendiente');
return response()->json([
'exito' => 1,
'id_cotizacion' => $id_cotizacion,
'folio' => $folio
]);
} catch (\Exception $e) {
DB::rollBack();
return response()->json([
'exito' => 0,
'error' => $e->getMessage()
], 500);
}
}
public function guardarPosibleCompra(Request $request)
{
$datos = $request->all();
// Generar un ID de cotización (solo numérico, aún no se inserta)
$id_cotizacion = DB::table('cotizaciones')->max('id_cotizacion') + 1;
$folio = 'COT' . str_pad($id_cotizacion, 7, '0', STR_PAD_LEFT);
// Guardar en posibles_compras (solo lo que tiene la tabla)
DB::table('posibles_compras')->insert([
'id_cotizacion' => $id_cotizacion,
'id_sitio_web' => 6,
'total_reservado' => $datos['total_compra'],
'total_reserva' => $datos['total_compra'],
'fecha_alta' => Carbon::now(),
]);
// Guardar TODOS los datos de la reserva en sesión (no en BD)
session()->put('reserva_pendiente', [
'id_cotizacion' => $id_cotizacion,
'folio' => $folio,
'datos' => $datos,
]);
return response()->json([
'exito' => 1,
'id_cotizacion' => $id_cotizacion
]);
}
//
/*
public function imprimirPaseAbordar(Request $request)
{
// dd($request->all());
$generator = new BarcodeGeneratorPNG();
$barcodeBase64 = base64_encode(
$generator->getBarcode('VG1025TEO2026', $generator::TYPE_CODE_128)
);
$barcodeImg = 'data:image/png;base64,' . $barcodeBase64;
$logo = public_path('assets/img/vueloenglobo/logo-vueloenglobo.png');
$html = '
<h1>Pase de Abordar</h1>
<p>PASE DE ABORDAR</p>
';
$data = [
'pasajero' => 'JAVIER ALONSO',
'fecha' => '25 MAY 2026',
'hora' => '05:30',
'zona' => 'SKY 01',
'folio' => 'VG1025',
'barcode' => $barcodeImg,
'logo' => $logo,
];
$pdf = Pdf::loadView('pdf.pases.pase-abordar', $data)->setPaper('letter', 'portrait');
return response()->streamDownload(fn() => print $pdf->output(), 'pase-de-abordar.pdf');
} */
public function imprimirPaseAbordar(Request $request)
{
// Log para ver qué está llegando (para debug)
\Log::info('Datos recibidos en imprimirPaseAbordar:', $request->all());
// Validación de los datos principales
$validated = $request->validate([
'reservation_id' => 'required',
'id_vuelo' => 'required|integer',
'vuelo_nombre' => 'nullable|string',
'vuelo_descripcion' => 'nullable|string',
'vuelo_hora' => 'nullable|string',
'fecha_vuelo' => 'nullable|string',
'fecha_libre' => 'boolean',
'adultos' => 'required|integer|min:1',
'ninios' => 'required|integer|min:0',
'responsable' => 'required|array',
'responsable.nombres' => 'required|string',
'responsable.apellidos' => 'required|string',
'responsable.email' => 'required|email',
'responsable.telefono' => 'required|string',
'pasajeros' => 'required|array|min:1',
'pasajeros.*.nombres' => 'required|string',
'pasajeros.*.apellidos' => 'required|string',
'pasajeros.*.fecha_nacimiento' => 'required|date',
'pasajeros.*.peso_kg' => 'required|numeric',
'pasajeros.*.tipo' => 'required|string|in:adulto,nino',
'servicios' => 'nullable|array',
'servicios.*.id' => 'required|integer',
'servicios.*.cantidad' => 'required|integer|min:1',
'servicios.*.precio' => 'required|numeric',
'servicios.*.descripcion' => 'nullable|string',
'subtotal_vuelo' => 'required|numeric',
'total_extras' => 'required|numeric',
'descuento' => 'nullable|numeric',
'total' => 'required|numeric',
'payment_email' => 'nullable|email',
'payment_phone' => 'nullable|string',
'payment_description' => 'nullable|string',
'moneda' => 'nullable|string',
'simbolo' => 'nullable|string',
'categoria' => 'nullable|string',
'incluye' => 'nullable|array',
'rating' => 'nullable|numeric',
'highlighted_text' => 'nullable|string',
'highlighted_bg_color' => 'nullable|string',
]);
try {
// Generar código de barras único
$generator = new BarcodeGeneratorPNG();
$barcodeNumber = $request->reservation_id . rand(1000, 9999);
$barcodeBase64 = base64_encode($generator->getBarcode($barcodeNumber, $generator::TYPE_CODE_128));
$barcodeImg = 'data:image/png;base64,' . $barcodeBase64;
// Logo en Base64
$logoPath = public_path('assets/img/vueloenglobo/logo-vueloenglobo.png');
$logoBase64 = '';
if (file_exists($logoPath)) {
$logoData = base64_encode(file_get_contents($logoPath));
$logoBase64 = 'data:image/png;base64,' . $logoData;
} else {
// Logo por defecto si no existe
$logoBase64 = 'https://placehold.co/60x60/4A63D2/white?text=SB';
}
// Obtener los pasajeros
$pasajeros = $request->pasajeros;
$pasajeroPrincipal = $pasajeros[0] ?? null;
$nombrePasajero = $pasajeroPrincipal
? strtoupper(($pasajeroPrincipal['nombres'] ?? '') . ' ' . ($pasajeroPrincipal['apellidos'] ?? ''))
: 'PASAJERO NO ESPECIFICADO';
// Formatear la fecha del vuelo - CORREGIDO
$fechaVueloFormateada = $request->fecha_vuelo;
if ($request->fecha_libre) {
$fechaVueloFormateada = 'POR CONFIRMAR';
} elseif ($fechaVueloFormateada) {
try {
// Intentar parsear fecha en formato dd/mm/YYYY
if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $fechaVueloFormateada)) {
$fechaCarbon = \Carbon\Carbon::createFromFormat('d/m/Y', $fechaVueloFormateada);
$fechaVueloFormateada = $fechaCarbon->format('d/m/Y');
}
// Intentar parsear fecha en formato YYYY-mm-dd
elseif (preg_match('/^\d{4}-\d{2}-\d{2}$/', $fechaVueloFormateada)) {
$fechaCarbon = \Carbon\Carbon::parse($fechaVueloFormateada);
$fechaVueloFormateada = $fechaCarbon->format('d/m/Y');
}
// Intentar parsear cualquier otro formato
else {
$fechaCarbon = \Carbon\Carbon::parse($fechaVueloFormateada);
$fechaVueloFormateada = $fechaCarbon->format('d/m/Y');
}
} catch (\Exception $e) {
\Log::warning('No se pudo parsear la fecha del vuelo: ' . $fechaVueloFormateada . ' - Error: ' . $e->getMessage());
$fechaVueloFormateada = date('d/m/Y'); // Usar fecha actual como fallback
}
} else {
$fechaVueloFormateada = date('d/m/Y'); // Fecha actual si no hay fecha
}
// Formatear hora del vuelo - CORREGIDO
$horaCita = '05:30 AM';
if ($request->vuelo_hora && !empty($request->vuelo_hora)) {
try {
// Intentar parsear hora en diferentes formatos
$horaCarbon = \Carbon\Carbon::parse($request->vuelo_hora);
$horaCita = $horaCarbon->format('h:i A');
} catch (\Exception $e) {
\Log::warning('No se pudo parsear la hora del vuelo: ' . $request->vuelo_hora);
$horaCita = $request->vuelo_hora; // Usar la hora tal como viene
}
}
// Datos del vuelo
$datosVuelo = [
'nombre_vuelo' => $request->vuelo_nombre ?? 'Vuelo en Globo',
'tipo_vuelo' => $request->categoria ?? 'Compartido',
'fecha_vuelo' => $fechaVueloFormateada,
'hora_cita' => $horaCita,
'lugar_despegue' => 'SKY BALLOONS ',
'duracion' => '40 min',
'piloto' => '',
'precio_total' => $request->total ?? 0,
'anticipo' => $request->total ?? 0,
'saldo_pendiente' => 0,
'limite_pago' => date('d/m/Y', strtotime('+7 days')),
];
// Datos del responsable
$responsable = $request->responsable;
$nombreResponsable = strtoupper(
($responsable['nombres'] ?? '') . ' ' . ($responsable['apellidos'] ?? '')
);
$emailResponsable = $responsable['email'] ?? '';
$telefonoResponsable = $responsable['telefono'] ?? '';
// Procesar servicios adicionales
$serviciosAdicionales = [];
if (!empty($request->servicios)) {
foreach ($request->servicios as $servicio) {
$serviciosAdicionales[] = [
'nombre' => $servicio['descripcion'] ?? 'Servicio adicional',
'cantidad' => $servicio['cantidad'] ?? 1,
'precio_unitario' => $servicio['precio'] ?? 0,
'precio_total' => ($servicio['cantidad'] ?? 1) * ($servicio['precio'] ?? 0),
'estado' => 'Contratado',
'clase' => 'contratado',
];
}
}
// Si no hay servicios adicionales contratados, mostrar algunos por defecto
if (empty($serviciosAdicionales)) {
$serviciosAdicionales = [
[
'nombre' => 'Fotografía profesional',
'cantidad' => 1,
'precio_unitario' => 500,
'precio_total' => 500,
'estado' => 'No contratado',
'clase' => 'no-contratado',
],
[
'nombre' => 'Video recuerdo',
'cantidad' => 1,
'precio_unitario' => 0,
'precio_total' => 0,
'estado' => 'No contratado',
'clase' => 'no-contratado',
],
];
}
// Procesar lo que incluye el vuelo
$incluye = [];
if (!empty($request->incluye)) {
foreach ($request->incluye as $item) {
$incluye[] = $item['titulo_item'] ?? $item['nombre'] ?? 'Item incluido';
}
}
// Resumen de pasajeros - CORREGIDO (manejo de fechas de nacimiento)
$resumenPasajeros = [];
foreach ($pasajeros as $pasajero) {
$fechaNacimientoFormateada = 'No especificada';
if (isset($pasajero['fecha_nacimiento']) && !empty($pasajero['fecha_nacimiento'])) {
try {
// Intentar parsear fecha de nacimiento
if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $pasajero['fecha_nacimiento'])) {
$fechaNac = \Carbon\Carbon::createFromFormat('d/m/Y', $pasajero['fecha_nacimiento']);
$fechaNacimientoFormateada = $fechaNac->format('d/m/Y');
} else {
$fechaNac = \Carbon\Carbon::parse($pasajero['fecha_nacimiento']);
$fechaNacimientoFormateada = $fechaNac->format('d/m/Y');
}
} catch (\Exception $e) {
\Log::warning('No se pudo parsear fecha de nacimiento: ' . $pasajero['fecha_nacimiento']);
$fechaNacimientoFormateada = $pasajero['fecha_nacimiento'];
}
}
$resumenPasajeros[] = [
'nombre_completo' => strtoupper(
($pasajero['nombres'] ?? '') . ' ' . ($pasajero['apellidos'] ?? '')
),
'tipo' => $pasajero['tipo'] ?? 'adulto',
'peso_kg' => $pasajero['peso_kg'] ?? 'No especificado',
'fecha_nacimiento' => $fechaNacimientoFormateada,
];
}
// Información de pago
$infoPago = [
'metodo' => 'Tarjeta de crédito/débito',
'email' => $request->payment_email ?? $emailResponsable,
'telefono' => $request->payment_phone ?? $telefonoResponsable,
'descripcion' => $request->payment_description ?? $request->vuelo_nombre ?? 'Reserva de vuelo',
'moneda' => $request->moneda ?? 'MXN',
'simbolo' => $request->simbolo ?? '$',
];
// Preparar todos los datos para la vista
$data = [
// Datos del vuelo
'nombre_vuelo' => $datosVuelo['nombre_vuelo'],
'tipo_vuelo' => $datosVuelo['tipo_vuelo'],
'fecha_vuelo' => $datosVuelo['fecha_vuelo'],
'hora_cita' => $datosVuelo['hora_cita'],
'lugar_despegue' => $datosVuelo['lugar_despegue'],
'duracion' => $datosVuelo['duracion'],
'piloto' => $datosVuelo['piloto'],
'highlighted_text' => $request->highlighted_text ?? '',
'highlighted_bg_color' => $request->highlighted_bg_color ?? '#2563eb',
'rating' => $request->rating ?? 0,
// Datos del responsable
'nombre_responsable' => $nombreResponsable,
'email_responsable' => $emailResponsable,
'telefono_responsable' => $telefonoResponsable,
// Datos de pasajeros
'nombre_pasajero' => $nombrePasajero,
'lista_pasajeros' => $pasajeros,
'resumen_pasajeros' => $resumenPasajeros,
// Totales y precios
'precio_total' => $datosVuelo['precio_total'],
'subtotal_vuelo' => $request->subtotal_vuelo ?? 0,
'total_extras' => $request->total_extras ?? 0,
'descuento' => $request->descuento ?? 0,
'anticipo' => $datosVuelo['anticipo'],
'saldo_pendiente' => $datosVuelo['saldo_pendiente'],
'limite_pago' => $datosVuelo['limite_pago'],
// Información de pago
'info_pago' => $infoPago,
// Servicios e inclusiones
'servicios_adicionales' => $serviciosAdicionales,
'incluye' => $incluye,
// Datos de la reserva
'folio_reserva' => $request->reservation_id,
'fecha_reserva' => now()->format('d/m/Y H:i:s'),
// Códigos e imágenes
'barcode' => $barcodeImg,
'barcode_number' => $barcodeNumber,
'logo' => $logoBase64,
// Datos adicionales
'adultos' => $request->adultos ?? 1,
'ninios' => $request->ninios ?? 0,
'total_pasajeros' => ($request->adultos ?? 0) + ($request->ninios ?? 0),
'vuelo_descripcion' => $request->vuelo_descripcion ?? '',
];
// Generar PDF
$pdf = Pdf::loadView('pdf.pases.pase-abordar', $data)
->setPaper('letter', 'portrait')
->setOptions([
'defaultFont' => 'sans-serif',
'isHtml5ParserEnabled' => true,
'isRemoteEnabled' => true,
'chroot' => public_path(),
]);
// Guardar una copia del PDF (opcional)
$pdfPath = storage_path('app/public/pases-abordar/');
if (!file_exists($pdfPath)) {
mkdir($pdfPath, 0755, true);
}
$pdfPathCompleto = $pdfPath . "pase_abordar_" . $request->reservation_id . "_" . date('Ymd_His') . ".pdf";
$pdf->save($pdfPathCompleto);
// Enviar correo con el pase de abordar (opcional - comentado)
try {
// Mail::to($emailResponsable)->send(new PaseAbordarMail($data, $pdf));
// \Log::info("Correo enviado a: {$emailResponsable}");
} catch (\Exception $e) {
\Log::error("Error enviando correo: " . $e->getMessage());
}
// Descargar el PDF
return $pdf->download("pase_abordar_" . $request->reservation_id . ".pdf");
} catch (\Exception $e) {
\Log::error('Error generando pase de abordar: ' . $e->getMessage());
\Log::error('Trace: ' . $e->getTraceAsString());
return response()->json([
'success' => false,
'message' => 'Error al generar el pase de abordar: ' . $e->getMessage()
], 500);
}
}
}