a
    UeiYR                     @   s:   d Z ddlmZmZ ddlZddlmZ G dd dZdS )u	  
Módulo de consultas SQL para Solicitudes de Vuelo.

Este módulo maneja todas las consultas relacionadas con:
- Consulta de catálogos (centros de costos)
- Validación de centros de costos
- Validación de proyectos en Epicor ERP
- Inserción de solicitudes de vuelo
- Inserción de pasajeros
- Inserción de opciones de vuelo

ESTRUCTURA DE TABLAS (ACTUALIZADA):
====================================

FR_FlightRequest:
- FlightRequestID (int, PK, IDENTITY)
- CentroCostos (nvarchar, NOT NULL)
- Proyecto (nvarchar, NULL)
- VigenciaProyecto (date, NULL)
- DescripcionMotivo (nvarchar, NOT NULL)
- Destino (nvarchar, NOT NULL)
- KilometrajeViaje (numeric, NULL)
- FechaSalida (date, NOT NULL)
- FechaRegreso (date, NULL)
- HoraAproxSalida (time, NOT NULL)
- HoraAproxRegreso (time, NULL)
- Estatus (nvarchar, NOT NULL, DEFAULT 'En Aprobacion')
  * Valores: 'En Aprobacion', 'En Atencion', 'Atendida'
- Resolucion (nvarchar, NULL)
  * Valores: NULL, 'Aprobada', 'Rechazada'
- ComentariosResolucion (nvarchar, NULL)
- CreatedAt (datetime, NOT NULL, DEFAULT GETDATE())
- UpdatedAt (datetime, NULL)
- Active (bit, NOT NULL, DEFAULT 1)

FR_FlightPassenger:
- FlightPassengerID (int, PK, IDENTITY)
- FlightRequestID (int, FK, NOT NULL)
- NombrePasajero (nvarchar, NOT NULL)
- NumeroEmpleado (nvarchar, NULL)
- Empresa (nvarchar, NOT NULL)
- FechaNacimiento (date, NOT NULL)
- TipoIdentificacion (nvarchar, NOT NULL)
- Nacionalidad (nvarchar, NOT NULL)
- CorreoElectronico (nvarchar, NOT NULL)
- Telefono (nvarchar, NOT NULL)
- NumeroPasaporte (nvarchar, NULL)
- VigenciaPasaporte (date, NULL)
- TieneVisaVigente (bit, NOT NULL, DEFAULT 0)
- TipoVisa (nvarchar, NULL)
- VigenciaVisa (date, NULL)
- PaisVisa (nvarchar, NULL)
- OrdenPasajero (int, NOT NULL)
- CreatedAt (datetime, NOT NULL, DEFAULT GETDATE())
- UpdatedAt (datetime, NULL)
- Active (bit, NOT NULL, DEFAULT 1)

FR_Flight:
- FlightID (int, PK, IDENTITY)
- FlightRequestID (int, FK, NOT NULL)
- Aerolinea (nvarchar, NOT NULL)
- NumeroVuelo (nvarchar, NULL)
- FechaVuelo (date, NOT NULL)
- CostoTotal (numeric, NOT NULL)
- RutaCarpetaVuelo (nvarchar, NULL)
- NombreArchivo (nvarchar, NULL)
- OrdenPreferencia (int, NULL)
- EsOpcionSugerida (bit, NOT NULL, DEFAULT 1)
- EsVueloComprado (bit, NOT NULL, DEFAULT 0)
- Estado (nvarchar, NULL)
- CodigoReservacion (nvarchar, NULL)
- FechaCompra (date, NULL)
- ObservacionesCompra (nvarchar, NULL)
- ComentariosVuelo (nvarchar, NULL)
- CreatedAt (datetime, NOT NULL, DEFAULT GETDATE())
- UpdatedAt (datetime, NULL)
- Active (bit, NOT NULL, DEFAULT 1)
    )get_connectionget_connectionERPN)datetimec                   @   sX   e Zd ZdZedd Zedd Zedd Zedd	 Zed
d Z	edd Z
dS )SolicitudVueloSQLu   
    Clase que contiene todas las consultas SQL para el módulo de Solicitud de Vuelos.
    Todos los métodos son estáticos para facilitar su uso sin necesidad de instanciar la clase.
    c               
   C   s   zht  } |  }d}|| | }|  |   g }|D ]}||d |d d q>d|ddW S  tjy } z"dg d	t| dW  Y d}~S d}~0  t	y } z"dg d
t| dW  Y d}~S d}~0 0 dS )a/  
        Obtiene todos los centros de costos activos de la base de datos.
        
        Returns:
            dict: {
                'success': bool,
                'centros': list de diccionarios con ceco y nombre,
                'error': str con mensaje de error (si falla)
            }
        z
                SELECT 
                    CeCo,
                    NombreCeCo
                FROM Cost_Centers
                WHERE Active = 1
                ORDER BY CeCo ASC
            r      )ZceconombreTN)successcentroserrorFz$Error al obtener centros de costos: Error inesperado: )
r   cursorexecutefetchallcloseappendpyodbcErrorstr	Exception)connr   query
resultadosr	   	resultadoe r   S/var/www/html/src/Consultas_SQL/Global/AdminSolicitudes/Vuelos/SolicitudVueloSQL.pyobtener_centros_costosd   s8    	

z(SolicitudVueloSQL.obtener_centros_costosc              
   C   s   zxt  }| }d}||| f | }|  |  |r`d|d |d |d dddW S d	dd
|  ddW S W nv tjy } z"d	ddt| dW  Y d}~S d}~0  t y } z"d	ddt| dW  Y d}~S d}~0 0 dS )u  
        Valida que el centro de costos exista y esté activo en la base de datos.
        
        Args:
            centro_costos (str): Código del centro de costos a validar
            
        Returns:
            dict: {
                'existe': bool,
                'datos': dict con información del centro de costos (si existe),
                'error': str con mensaje de error (si falla)
            }
        z
                SELECT 
                    CeCo,
                    NombreCeCo,
                    Active
                FROM Cost_Centers
                WHERE CeCo = ?
                  AND Active = 1
            Tr   r      )ZCeCo
NombreCeCoActiveN)existedatosr
   FzCentro de costos "z" no encontrado o inactivoz#Error al validar centro de costos: r   )	r   r   r   fetchoner   r   r   r   r   )centro_costosr   r   r   r   r   r   r   r   validar_centro_costos   s<    

z'SolicitudVueloSQL.validar_centro_costosc                 C   s(  zt  }| }d}||| f | }|  |  |rd|d dk|d |d |d |d |d	 |d
 |d |d |d d	ddW S dddd|  ddW S W nz tjy } z$ddddt| dW  Y d}~S d}~0  ty" } z$ddddt| dW  Y d}~S d}~0 0 dS )u  
        Valida que el proyecto exista en Epicor ERP y esté vigente.
        
        Args:
            proyecto_id (str): ID del proyecto en Epicor
            
        Returns:
            dict: {
                'existe': bool,
                'vigente': bool,
                'datos': dict con información del proyecto (si existe),
                'error': str con mensaje de error (si falla)
            }
        a  
                SELECT 
                    Project.ProjectID,
                    Project.Description AS NombreProyecto,
                    OrderDtl.OrderNum,
                    OrderHed.CustNum,
                    OrderHed.OrderDate,
                    OrderHed.OrderAmt,
                    OrderHed.OpenOrder,
                    OrderHed.VoidOrder,
                    CASE 
                        WHEN OrderHed.OpenOrder = 1 AND OrderHed.VoidOrder = 0 
                            THEN 'VIGENTE'
                        ELSE 'NO VIGENTE'
                    END AS Estado
                FROM Erp.Project AS Project
                INNER JOIN Erp.OrderDtl AS OrderDtl
                    ON Project.Company = OrderDtl.Company
                    AND Project.ProjectID = OrderDtl.ProjectID
                INNER JOIN Erp.OrderHed AS OrderHed
                    ON OrderDtl.Company = OrderHed.Company
                    AND OrderDtl.OrderNum = OrderHed.OrderNum
                WHERE 
                    Project.Company = 'IGSA'
                    AND Project.ProjectID = ?
                    AND OrderHed.OpenOrder = 1
                    AND OrderHed.VoidOrder = 0
            T   ZVIGENTEr   r   r                  )		ProjectIDNombreProyectoOrderNumCustNum	OrderDateZOrderAmtZ	OpenOrderZ	VoidOrderZEstadoN)r    vigenter!   r
   Fz
Proyecto "u,   " no encontrado o no tiene órdenes vigentesz"Error al validar proyecto en ERP: r   )	r   r   r   r"   r   r   r   r   r   )Zproyecto_idr   r   r   r   r   r   r   r   validar_proyecto_erp   sP    

z&SolicitudVueloSQL.validar_proyecto_erpc                 C   s\  d}zt  }| }d}||| d| d| d| d| d| d| d	| d
| d| df
 |d t| d }d|d}|  |  |  d||ddW S  tj	y } z0|r|
  ddddt| dW  Y d}~S d}~0  tyV } z2|r*|
  ddddt| dW  Y d}~S d}~0 0 dS )a  
        Inserta una nueva solicitud de vuelo en la tabla FR_FlightRequest.
        
        Args:
            datos_solicitud (dict): Diccionario con los datos de la solicitud
                
        Returns:
            dict: {
                'success': bool,
                'flight_request_id': int (ID generado),
                'folio': str (folio generado),
                'error': str (si falla)
            }
        Nal  
                INSERT INTO FR_FlightRequest (
                    CentroCostos,
                    Proyecto,
                    VigenciaProyecto,
                    DescripcionMotivo,
                    Destino,
                    KilometrajeViaje,
                    FechaSalida,
                    FechaRegreso,
                    HoraAproxSalida,
                    HoraAproxRegreso,
                    Estatus,
                    Active
                ) VALUES (
                    ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
                    'En Aprobacion',
                    1
                )
            CentroCostosProyectoVigenciaProyectoDescripcionMotivoDestinoKilometrajeViajeFechaSalidaFechaRegresoHoraAproxSalidaHoraAproxRegresozSELECT @@IDENTITYr   zFLT-06dT)r   flight_request_idfolior
   FzError al insertar solicitud: r   )r   r   r   getintr"   commitr   r   r   rollbackr   r   )datos_solicitudr   r   r   r=   r>   r   r   r   r   insertar_solicitudF  sX    
z$SolicitudVueloSQL.insertar_solicitudc                 C   s@  d}zt  }| }d}d}|D ]b}||| |d|d|d|d|d|d	|d
|d|df
 |d7 }q |  |  |  d|ddW S  tj y } z.|r|  dddt	| dW  Y d}~S d}~0  t
y: } z0|r|  dddt	| dW  Y d}~S d}~0 0 dS )u  
        Inserta múltiples pasajeros asociados a una solicitud de vuelo.
        
        Args:
            flight_request_id (int): ID de la solicitud de vuelo
            lista_pasajeros (list): Lista de diccionarios con datos de pasajeros
                
        Returns:
            dict: {
                'success': bool,
                'insertados': int (cantidad de pasajeros insertados),
                'error': str (si falla)
            }
        Na1  
                INSERT INTO FR_FlightPassenger (
                    FlightRequestID,
                    NombrePasajero,
                    NumeroEmpleado,
                    Empresa,
                    FechaNacimiento,
                    TipoIdentificacion,
                    Nacionalidad,
                    CorreoElectronico,
                    Telefono,
                    OrdenPasajero,
                    Active
                ) VALUES (
                    ?, ?, ?, ?, ?, ?, ?, ?, ?, ? 
                    , 1
                )
            r   NombrePasajeroNumeroEmpleadoEmpresaFechaNacimientoTipoIdentificacionNacionalidadCorreoElectronicoTelefonoOrdenPasajeror   Tr   
insertadosr
   FzError al insertar pasajeros: r   )r   r   r   r?   rA   r   r   r   rB   r   r   )r=   lista_pasajerosr   r   r   rO   pasajeror   r   r   r   insertar_pasajeros  sR    
z$SolicitudVueloSQL.insertar_pasajerosc           	      C   sB  d}zt  }| }d}d}|D ]d}|d}|sL|d| f | d }||| |d|d||d|d	f |d
7 }q |  |  |  d|ddW S  tj y } z.|r|	  dddt
| dW  Y d}~S d}~0  ty< } z0|r|	  dddt
| dW  Y d}~S d}~0 0 dS )u  
        Inserta múltiples opciones de vuelo asociadas a una solicitud.
        
        Args:
            flight_request_id (int): ID de la solicitud de vuelo
            lista_vuelos (list): Lista de diccionarios con datos de vuelos
                
        Returns:
            dict: {
                'success': bool,
                'insertados': int (cantidad de vuelos insertados),
                'error': str (si falla)
            }
        Na  
                INSERT INTO FR_Flight (
                    FlightRequestID,
                    Aerolinea,
                    NumeroVuelo,
                    FechaVuelo,
                    CostoTotal,
                    OrdenPreferencia,
                    EsOpcionSugerida,
                    EsVueloComprado,
                    Active
                ) VALUES (
                    ?, ?, ?, ?, ?, ?, 1, 0, 1
                )
            r   
FechaVueloz
                        SELECT FechaSalida 
                        FROM FR_FlightRequest 
                        WHERE FlightRequestID = ?
                    	AerolineaNumeroVuelo
CostoTotalOrdenPreferenciar   TrN   Fz%Error al insertar opciones de vuelo: r   )r   r   r?   r   r"   rA   r   r   r   rB   r   r   )	r=   lista_vuelosr   r   r   rO   vueloZfecha_vuelor   r   r   r   insertar_vuelos  sV    

z!SolicitudVueloSQL.insertar_vuelosN)__name__
__module____qualname____doc__staticmethodr   r$   r1   rD   rR   rZ   r   r   r   r   r   Z   s   	
<
@
c
b
Yr   )r^   Consultas_SQL.conexionr   r   r   r   r   r   r   r   r   <module>   s   O