584 lines
21 KiB
PHP
584 lines
21 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Pase de Abordar | Vuelo en Globo</title>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
|
<style>
|
|
@page {
|
|
size: letter;
|
|
margin: 0.6cm 0.7cm;
|
|
}
|
|
|
|
/* RESET + BASE MODERNA */
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
background: #F0F4F8;
|
|
font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, BlinkMacSystemFont, 'Roboto', sans-serif;
|
|
font-size: 9pt;
|
|
line-height: 1.4;
|
|
color: #1A2C3E;
|
|
padding: 0;
|
|
}
|
|
|
|
/* Contenedor principal carta */
|
|
.boarding-container {
|
|
max-width: 100%;
|
|
background: white;
|
|
border-radius: 28px;
|
|
overflow: hidden;
|
|
box-shadow: 0 20px 35px -12px rgba(0, 0, 0, 0.2);
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
/* ========= TABLAS PRINCIPALES (compatibles dompdf) ========= */
|
|
.full-width-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
/* Header superior moderno */
|
|
.top-header {
|
|
background: linear-gradient(105deg, #1D3557 0%, #2A6F8F 100%);
|
|
color: white;
|
|
border-bottom: 2px solid #FFD966;
|
|
}
|
|
|
|
.logo-cell {
|
|
padding: 14px 18px;
|
|
width: 35%;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.badge-cell {
|
|
padding: 14px 18px;
|
|
text-align: right;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.logo-img {
|
|
max-height: 48px;
|
|
width: auto;
|
|
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));
|
|
}
|
|
|
|
.company-sub {
|
|
font-size: 7.5px;
|
|
letter-spacing: 1px;
|
|
font-weight: 500;
|
|
display: block;
|
|
margin-top: 4px;
|
|
opacity: 0.85;
|
|
}
|
|
|
|
.boarding-badge {
|
|
background: rgba(255,255,240,0.2);
|
|
backdrop-filter: blur(2px);
|
|
padding: 6px 16px;
|
|
border-radius: 100px;
|
|
font-weight: 700;
|
|
font-size: 11px;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
border: 1px solid rgba(255,255,200,0.4);
|
|
}
|
|
|
|
/* TICKET PRINCIPAL */
|
|
.ticket-card {
|
|
background: white;
|
|
}
|
|
|
|
/* Cabecera vuelo (dentro del ticket) */
|
|
.flight-header-table {
|
|
width: 100%;
|
|
background: #FFFFFF;
|
|
border-bottom: 1px solid #E9EEF2;
|
|
}
|
|
|
|
.flight-brand-cell {
|
|
padding: 16px 20px 8px 20px;
|
|
}
|
|
|
|
.flight-title-cell {
|
|
padding: 16px 20px 8px 20px;
|
|
text-align: right;
|
|
}
|
|
|
|
.boarding-pass-title {
|
|
font-weight: 800;
|
|
font-size: 18px;
|
|
background: linear-gradient(135deg, #1D3557, #2A9D8F);
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
color: transparent;
|
|
display: inline-block;
|
|
}
|
|
.dompdf-fallback {
|
|
color: #1D3557;
|
|
}
|
|
|
|
/* Info Grid principal con tabla */
|
|
.info-section-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 6px;
|
|
background: #F9FCFE;
|
|
border-radius: 20px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.info-section-table td {
|
|
padding: 12px 14px;
|
|
border-right: 1px solid #E4ECF3;
|
|
vertical-align: top;
|
|
width: 25%;
|
|
}
|
|
.info-section-table tr td:last-child {
|
|
border-right: none;
|
|
}
|
|
|
|
.info-label {
|
|
font-size: 7.5px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.6px;
|
|
color: #4682B4;
|
|
margin-bottom: 5px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
}
|
|
.info-value {
|
|
font-size: 12px;
|
|
font-weight: 700;
|
|
color: #0B2B3D;
|
|
word-break: break-word;
|
|
}
|
|
.status-badge {
|
|
background: #D4F1F4;
|
|
color: #0F6B6B;
|
|
padding: 3px 8px;
|
|
border-radius: 20px;
|
|
display: inline-block;
|
|
font-size: 9px;
|
|
font-weight: 800;
|
|
}
|
|
|
|
/* Ruta moderna (flex + tabla híbrido pero uso divs internos seguros) */
|
|
.route-modern {
|
|
background: linear-gradient(120deg, #FEF9E8 0%, #FFF3E0 100%);
|
|
border-radius: 24px;
|
|
margin: 12px 0 8px 0;
|
|
padding: 12px 0;
|
|
}
|
|
.route-table {
|
|
width: 100%;
|
|
text-align: center;
|
|
border-collapse: collapse;
|
|
}
|
|
.route-table td {
|
|
padding: 6px;
|
|
}
|
|
.city-code {
|
|
font-size: 28px;
|
|
font-weight: 900;
|
|
color: #2C5F8A;
|
|
letter-spacing: 1px;
|
|
}
|
|
.city-name {
|
|
font-size: 8px;
|
|
font-weight: 600;
|
|
color: #5D6E7A;
|
|
}
|
|
.balloon-icon-big {
|
|
font-size: 36px;
|
|
color: #F4A261;
|
|
}
|
|
|
|
/* inclusiones diseño card */
|
|
.inclusions-card {
|
|
background: #EFF6FA;
|
|
border-left: 6px solid #2A9D8F;
|
|
border-radius: 20px;
|
|
padding: 12px 16px;
|
|
margin: 12px 0 6px;
|
|
}
|
|
.inclusions-list {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
.inclusions-list td {
|
|
padding: 6px 6px 6px 0;
|
|
font-size: 8.5px;
|
|
font-weight: 500;
|
|
color: #1F4E6E;
|
|
}
|
|
.inclusions-list i {
|
|
width: 20px;
|
|
color: #2A9D8F;
|
|
}
|
|
|
|
/* Tabla de pasajeros lista */
|
|
.passengers-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
background: #F9F9FF;
|
|
border-radius: 18px;
|
|
}
|
|
.passengers-table td {
|
|
padding: 6px 12px;
|
|
border-bottom: 1px solid #E2E8F0;
|
|
}
|
|
.passenger-tag {
|
|
background: white;
|
|
border-radius: 40px;
|
|
padding: 4px 12px;
|
|
display: inline-block;
|
|
font-size: 8px;
|
|
font-weight: 600;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
|
margin: 2px 4px 2px 0;
|
|
}
|
|
|
|
/* servicios adicionales */
|
|
.services-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
background: #FFFFFF;
|
|
border-radius: 20px;
|
|
overflow: hidden;
|
|
border: 1px solid #E9EDF2;
|
|
}
|
|
.services-table td {
|
|
padding: 8px 12px;
|
|
border-bottom: 1px solid #EDF2F7;
|
|
}
|
|
.service-price {
|
|
font-weight: 800;
|
|
color: #2C7A6E;
|
|
text-align: right;
|
|
}
|
|
.no-contratado {
|
|
color: #A0AEC0;
|
|
font-style: italic;
|
|
}
|
|
|
|
/* tabla de pagos estilo summary */
|
|
.payment-summary-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
background: #FFFFFF;
|
|
border-radius: 20px;
|
|
overflow: hidden;
|
|
box-shadow: 0 2px 6px rgba(0,0,0,0.03);
|
|
}
|
|
.payment-summary-table tr td {
|
|
padding: 9px 16px;
|
|
border-bottom: 1px solid #EFF3F8;
|
|
}
|
|
.total-row-pay {
|
|
background: #1D3557;
|
|
color: white;
|
|
font-weight: 800;
|
|
border-radius: 0 0 16px 16px;
|
|
}
|
|
.deadline-text {
|
|
text-align: right;
|
|
font-size: 7.5px;
|
|
font-weight: 600;
|
|
color: #E76F51;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
/* instrucciones modernas */
|
|
.instruction-grid {
|
|
background: #F8F9FC;
|
|
border-radius: 24px;
|
|
margin: 12px 0;
|
|
padding: 6px 12px;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: space-between;
|
|
}
|
|
.instruction-chip {
|
|
background: white;
|
|
border-radius: 60px;
|
|
padding: 4px 12px;
|
|
font-size: 7.5px;
|
|
font-weight: 600;
|
|
color: #2C3E50;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
|
}
|
|
|
|
/* código de barras + footer */
|
|
.barcode-area {
|
|
text-align: center;
|
|
margin: 14px 0 6px;
|
|
}
|
|
.barcode-img {
|
|
max-width: 230px;
|
|
height: auto;
|
|
}
|
|
.ref-code {
|
|
text-align: center;
|
|
font-family: monospace;
|
|
letter-spacing: 1.5px;
|
|
font-size: 9px;
|
|
background: #F3F6FC;
|
|
display: inline-block;
|
|
padding: 4px 16px;
|
|
border-radius: 30px;
|
|
}
|
|
.footer-ticket-modern {
|
|
background: #F1F5F9;
|
|
padding: 14px 20px;
|
|
border-top: 1px solid #DFE7EF;
|
|
}
|
|
.footer-flex {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
.footer-brand-modern {
|
|
font-weight: 800;
|
|
color: #2C5F8A;
|
|
}
|
|
.page-footer-modern {
|
|
margin-top: 12px;
|
|
text-align: center;
|
|
font-size: 7px;
|
|
border-top: 1px solid #CFDFE9;
|
|
padding-top: 12px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
color: #5F7F9A;
|
|
}
|
|
|
|
/* ajustes para borde redondeado general */
|
|
.rounded-ticket {
|
|
border-radius: 28px;
|
|
}
|
|
.spacer {
|
|
height: 2px;
|
|
}
|
|
i {
|
|
margin-right: 3px;
|
|
}
|
|
/* garantizar tablas responsivas dentro de carta */
|
|
@media print {
|
|
body {
|
|
background: white;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
.boarding-container {
|
|
box-shadow: none;
|
|
border-radius: 0;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="boarding-container">
|
|
<!-- HEADER SUPERIOR CON TABLA (MODERNO) -->
|
|
<table class="full-width-table top-header">
|
|
<tr>
|
|
<td class="logo-cell">
|
|
@if($logo)
|
|
<img src="{{ $logo }}" alt="Vuelo en Globo" class="logo-img">
|
|
@else
|
|
<div style="font-weight:800; font-size: 18px;">VUELO EN GLOBO</div>
|
|
@endif
|
|
<div class="company-sub"><i class="fas fa-cloud-moon"></i> AEROSTATIC EXPERIENCES</div>
|
|
</td>
|
|
<td class="badge-cell">
|
|
<div class="boarding-badge">
|
|
<i class="fas fa-ticket-alt"></i> PASE DE ABORDAR · PRIORITY
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<!-- TICKET PRINCIPAL CARD -->
|
|
<div class="ticket-card">
|
|
<!-- Cabecera interna vuelo -->
|
|
<table class="flight-header-table">
|
|
<tr>
|
|
<td class="flight-brand-cell">
|
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
@if($logo)
|
|
<img src="{{ $logo }}" style="height: 32px;" alt="logo">
|
|
@else
|
|
<i class="fas fa-balloon" style="font-size: 28px; color:#1D3557;"></i>
|
|
@endif
|
|
<div>
|
|
<div class="boarding-pass-title dompdf-fallback">BOARDING PASS</div>
|
|
<div style="font-size: 7px; color:#5F7A92;">ELECTRÓNICO · VÁLIDO PARA ABORDAR</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td class="flight-title-cell">
|
|
<span style="background: #EFF3F8; padding: 4px 16px; border-radius: 40px; font-size: 11px; font-weight:800;">
|
|
<i class="fas fa-plane-departure"></i> ABORDAR
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<!-- CUERPO DETALLES (TABLAS) -->
|
|
<div style="padding: 0 18px 10px 18px;">
|
|
<!-- Pasajero principal -->
|
|
<div style="margin: 8px 0 6px 0;">
|
|
<div class="info-label"><i class="fas fa-user-astronaut"></i> PASAJERO PRINCIPAL</div>
|
|
<div class="info-value" style="font-size: 14px;">{{ $nombre_pasajero }}</div>
|
|
</div>
|
|
|
|
<!-- Tabla información vuelo -->
|
|
<table class="info-section-table">
|
|
<tr>
|
|
<td><div class="info-label"><i class="fas fa-fan"></i> VUELO</div><div class="info-value">{{ $nombre_vuelo }}</div></td>
|
|
<td><div class="info-label"><i class="fas fa-users"></i> TIPO</div><div class="info-value">{{ $tipo_vuelo }}</div></td>
|
|
<td><div class="info-label"><i class="fas fa-calendar-alt"></i> FECHA</div><div class="info-value">{{ $fecha_vuelo === 'POR CONFIRMAR' ? $fecha_vuelo : (\Carbon\Carbon::createFromFormat('d/m/Y', $fecha_vuelo)->format('d M Y')) }}</div></td>
|
|
<td><div class="info-label"><i class="fas fa-check-circle"></i> ESTADO</div><div class="info-value"><span class="status-badge"><i class="fas fa-check"></i> CONFIRMADO</span></div></td>
|
|
</tr>
|
|
</table>
|
|
<table class="info-section-table" style="margin-top: 5px;">
|
|
<tr>
|
|
<td><div class="info-label"><i class="fas fa-clock"></i> HORA CITA</div><div class="info-value">{{ $hora_cita }}</div></td>
|
|
<td><div class="info-label"><i class="fas fa-map-marker-alt"></i> DESPEGUE</div><div class="info-value">{{ $lugar_despegue }}</div></td>
|
|
<td><div class="info-label"><i class="fas fa-hourglass-half"></i> DURACIÓN</div><div class="info-value">{{ $duracion }}</div></td>
|
|
<td><div class="info-label"><i class="fas fa-user-tie"></i> PILOTO</div><div class="info-value">{{ $piloto }}</div></td>
|
|
</tr>
|
|
</table>
|
|
|
|
<!-- Ruta moderna con tabla interna -->
|
|
<div class="route-modern">
|
|
<table class="route-table">
|
|
<tr>
|
|
<td><span class="city-code">MEX</span><div class="city-name"><i class="fas fa-city"></i> Ciudad de México</div></td>
|
|
<td><div class="balloon-icon-big"><i class="fas fa-balloon"></i></div><div style="font-size: 7px; color:#E76F51;">VUELO DIRECTO</div></td>
|
|
<td><span class="city-code">TEOTIHUACÁN</span><div class="city-name"><i class="fas fa-landmark"></i> Teotihuacán</div></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Incluye / Inclusiones -->
|
|
<div class="inclusions-card">
|
|
<div class="info-label" style="color:#1E6F5C;"><i class="fas fa-gift"></i> EXPERIENCIA INCLUYE</div>
|
|
<table class="inclusions-list">
|
|
<tr><td><i class="fas fa-balloon"></i> Vuelo compartido 40-60 min + Brindis espumoso</td></tr>
|
|
<tr><td><i class="fas fa-certificate"></i> Certificado de vuelo · Café y galletas</td></tr>
|
|
<tr><td><i class="fas fa-shuttle-van"></i> Traslado de regreso al punto de reunión</td></tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Lista completa de pasajeros -->
|
|
@if(count($lista_pasajeros) > 1)
|
|
<div style="margin: 12px 0 4px;">
|
|
<div class="info-label"><i class="fas fa-users-viewfinder"></i> TODOS LOS AERONAUTAS</div>
|
|
<table class="passengers-table">
|
|
@foreach($lista_pasajeros as $pasajero)
|
|
<tr>
|
|
<td><i class="fas fa-user-circle"></i> {{ $pasajero['nombres'] }} {{ $pasajero['apellidos'] }}</td>
|
|
<td style="text-align: right;"><span class="passenger-tag">{{ $pasajero['tipo'] == 'adulto' ? 'Adulto' : 'Niño' }}</span></td>
|
|
</tr>
|
|
@endforeach
|
|
</table>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Servicios adicionales (CORREGIDO: se usa precio_unitario en lugar de precio) -->
|
|
<div style="margin: 10px 0 6px;">
|
|
<div class="info-label"><i class="fas fa-camera-retro"></i> SERVICIOS ADICIONALES</div>
|
|
<table class="services-table">
|
|
@foreach($servicios_adicionales as $servicio)
|
|
<tr>
|
|
<td style="width: 70%;">
|
|
<i class="fas {{ strpos($servicio['nombre'], 'Foto') !== false ? 'fa-camera' : (strpos($servicio['nombre'], 'Video') !== false ? 'fa-video' : 'fa-plus-circle') }}"></i>
|
|
{{ $servicio['nombre'] }}
|
|
</td>
|
|
<td class="service-price">
|
|
@if($servicio['estado'] == 'Contratado')
|
|
+${{ number_format($servicio['precio_unitario'], 0) }} MXN
|
|
@else
|
|
<span class="no-contratado">No contratado</span>
|
|
@endif
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Resumen Pagos con Tabla Elegante -->
|
|
<div style="margin: 8px 0 4px;">
|
|
<div class="info-label"><i class="fas fa-coins"></i> RESUMEN DE PAGOS</div>
|
|
<table class="payment-summary-table">
|
|
<tr><td style="width: 65%;">Total del vuelo</td><td style="text-align: right; font-weight:700;">${{ number_format($precio_total, 2) }} MXN</td></tr>
|
|
<tr><td>Anticipo aplicado</td><td style="text-align: right; color:#2C7A6E;">-${{ number_format($anticipo, 2) }} MXN</td></tr>
|
|
<tr class="total-row-pay"><td style="font-weight: 800;">SALDO PENDIENTE</td><td style="text-align: right; font-weight: 800;">${{ number_format($saldo_pendiente, 2) }} MXN</td></tr>
|
|
</table>
|
|
<div class="deadline-text">
|
|
<i class="fas fa-hourglass-half"></i> FECHA LÍMITE DE PAGO:
|
|
@php
|
|
$limiteMostrar = $limite_pago;
|
|
if ($limite_pago && $limite_pago !== 'POR CONFIRMAR') {
|
|
try {
|
|
if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $limite_pago)) {
|
|
$limiteMostrar = \Carbon\Carbon::createFromFormat('d/m/Y', $limite_pago)->format('d M Y');
|
|
} else {
|
|
$limiteMostrar = \Carbon\Carbon::parse($limite_pago)->format('d M Y');
|
|
}
|
|
} catch (\Exception $e) {
|
|
$limiteMostrar = $limite_pago;
|
|
}
|
|
}
|
|
@endphp
|
|
{{ $limiteMostrar }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Instrucciones chips UX-->
|
|
<div class="instruction-grid">
|
|
<span class="instruction-chip"><i class="fas fa-hourglass-start"></i> Llegar 30 min antes</span>
|
|
<span class="instruction-chip"><i class="fas fa-id-card"></i> Identificación oficial</span>
|
|
<span class="instruction-chip"><i class="fas fa-vest"></i> Chamarra / Ropa cómoda</span>
|
|
<span class="instruction-chip"><i class="fas fa-cloud-sun"></i> Sujeto a condiciones climáticas</span>
|
|
</div>
|
|
|
|
<!-- BARCODE Y FOLIO -->
|
|
<div class="barcode-area">
|
|
<img class="barcode-img" src="{{ $barcode }}" alt="Código de barras QR">
|
|
<div style="margin-top: 4px;"><span class="ref-code"><i class="fas fa-hashtag"></i> RESERVA: {{ $folio_reserva }}</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- FOOTER TICKET -->
|
|
<div class="footer-ticket-modern">
|
|
<div class="footer-flex">
|
|
<div>
|
|
<div class="footer-brand-modern"><i class="fas fa-globe-americas"></i> VUELOENGLOBO.MX</div>
|
|
<div style="font-size: 6.5px; max-width: 280px;">Válido solo para la fecha asignada. Reprogramación gratuita por condiciones climáticas o seguridad.</div>
|
|
</div>
|
|
<div><i class="fas fa-balloon" style="font-size: 32px; color:#2A9D8F;"></i></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- PIE DE PÁGINA GENERAL -->
|
|
<div class="page-footer-modern">
|
|
<div><i class="fas fa-phone-alt"></i> (55) 1234 5678 | <i class="fas fa-envelope"></i> reservaciones@vueloenglobo.mx</div>
|
|
<div><i class="fab fa-instagram"></i> @vueloenglobo | <i class="fas fa-location-dot"></i> Teotihuacán, Méx.</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html> |