a
    TeiñF  ã                   @   s   d Z ddlZddlZddlmZmZmZ ej ej ej ej ej 	e
¡¡¡¡¡ ddlmZ G dd„ dƒZddd	„Zddd„Zddd„ZdS )už  
MÃ³dulo de ValidaciÃ³n de Reglas Globales.

Este mÃ³dulo proporciona un validador genÃ©rico que evalÃºa datos contra
reglas definidas en la tabla RulesGlobal de la base de datos.

CaracterÃ­sticas:
- ValidaciÃ³n por mÃ³dulo completo
- ValidaciÃ³n de reglas especÃ­ficas
- Soporte para operadores: >, <, >=, <=, =, !=, BETWEEN
- Soporte para tipos de datos: Number, Date
- Mensajes de error configurables desde BD
é    N)ÚdatetimeÚdateÚ	timedelta)ÚRulesGlobalSQLc                   @   sH   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
dS )ÚRulesValidatoruG  
    Validador genÃ©rico de reglas de negocio.
    
    Esta clase permite validar datos contra reglas definidas en la tabla RulesGlobal.
    Soporta validaciÃ³n por mÃ³dulo completo o por regla especÃ­fica.
    
    Ejemplo de uso:
        validator = RulesValidator()
        
        # Validar todo un mÃ³dulo
        resultado = validator.validar_reglas('FR_FlightRequest', {
            'kilometraje': 350,
            'fecha_salida': '2025-01-20'
        })
        
        # Validar regla especÃ­fica
        resultado = validator.validar_regla_especifica('KM_MIN', 350)
    c                 C   s   t ƒ | _dS )z"Inicializa el validador de reglas.N)r   Úsql©Úself© r
   ú5/var/www/html/src/App/Utilities_module/RulesGlobal.pyÚ__init__2   s    zRulesValidator.__init__c                 C   s0  t dd› ƒ t d|› ƒ t d› ƒ g }d}d}| j |¡}|d srt d|d › ƒ dd	|d › gddd
œS |d }|sšt d|› ƒ dg ddd
œS t dt|ƒ› ƒ |D ]ð}|d7 }|d }	t dd› ƒ t d|	› d|d › ƒ |	|vrt d|	› dƒ q°||	 }
t d|
› ƒ t d|d › ƒ t d|d › ƒ | j|d |
|d |d |d d}|d s˜|d7 }|d  }| |¡ t d!|› ƒ q°t d"ƒ q°t dd› ƒ t d#ƒ t d› ƒ t d$|› ƒ t d%|| › ƒ t d&|› ƒ t d'|dkrd(nd)› ƒ t d› dƒ t|ƒdk|||d
œS )*uR  
        Valida todas las reglas activas de un mÃ³dulo especÃ­fico.
        
        Este mÃ©todo obtiene todas las reglas del mÃ³dulo desde la BD y
        valida los datos proporcionados contra cada regla.
        
        Args:
            module_id (str): ID del mÃ³dulo (ej: 'FR_FlightRequest')
            datos (dict): Diccionario con los datos a validar
                         Las keys deben coincidir con los RuleCode
                         
        Returns:
            dict: {
                'valido': bool,           # True si todas las reglas pasan
                'errores': list,          # Lista de mensajes de error
                'reglas_evaluadas': int,  # Cantidad de reglas evaluadas
                'reglas_fallidas': int    # Cantidad de reglas que fallaron
            }
            
        Ejemplo:
            datos = {
                'KM_MIN': 350,              # Para regla de kilometraje mÃ­nimo
                'ANTICIP_DIAS': '2025-01-20' # Para regla de anticipaciÃ³n
            }
            resultado = validator.validar_reglas('FR_FlightRequest', datos)
        Ú
zP================================================================================u#   ðŸ” VALIDANDO REGLAS DEL MÃ“DULO: r   Úsuccessu   âŒ Error al obtener reglas: ÚerrorFzError al cargar reglas: )ÚvalidoÚerroresÚreglas_evaluadasÚreglas_fallidasÚreglasu3   â„¹ï¸  No hay reglas configuradas para el mÃ³dulo Tu   ðŸ“‹ Reglas encontradas: é   ZRuleCodeuð   â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€zEvaluando regla: z - ZRuleNameu   âš ï¸  Dato 'u5   ' no proporcionado en los datos, saltando validaciÃ³nz   Valor a validar: z   Operador: ÚComparisonOperatorz   Valor esperado: Ú	RuleValueÚ
RuleValue2Ú	ValueType©ÚoperatorÚvalor_actualÚvalor_esperadoÚvalor_esperado2Ú
value_typer   ÚMessageIfViolatedu      âŒ FALLA: u      âœ… PASAu   ðŸ“Š RESUMEN DE VALIDACIÃ“Nz   Reglas evaluadas: z   Reglas que pasaron: z   Reglas que fallaron: z   Resultado: u   âœ… VÃLIDOu   âŒ INVÃLIDO)Úprintr   Zobtener_reglas_por_moduloÚlenÚ_validar_comparacionÚappend)r	   Ú	module_idÚdatosr   r   r   Úresultado_sqlr   ÚreglaÚ	rule_coder   Úresultado_validacionÚmensaje_errorr
   r
   r   Úvalidar_reglas:   sz    
üü
û




üzRulesValidator.validar_reglasc                 C   s¶   t d|› ƒ t d|› ƒ | j |¡}|d sPt d|d › ƒ d|d dœS |d }| j|d	 ||d
 |d |d d}|d s¤|d }t d|› ƒ d|dœS t dƒ dddœS )uq  
        Valida una regla especÃ­fica por su cÃ³digo.
        
        Args:
            rule_code (str): CÃ³digo de la regla (ej: 'KM_MIN')
            valor: Valor a validar (puede ser int, float, str, date)
            
        Returns:
            dict: {
                'valido': bool,
                'mensaje': str (solo si no es vÃ¡lido)
            }
        u#   
ðŸ” Validando regla especÃ­fica: z
   Valor: r   u   âŒ Error: r   F©r   Úmensajer(   r   r   r   r   r   r   r    u   âŒ FALLA: u   âœ… PASATN)r!   r   Zobtener_regla_por_codigor#   )r	   r)   Úvalorr'   r(   r*   r.   r
   r
   r   Úvalidar_regla_especifica®   s4    þûþþz'RulesValidator.validar_regla_especificac              
   C   s,  zì|   ||¡}|   ||¡}|dkr2|r2|   ||¡}|dkrD||k}	nž|dkrV||k }	nŒ|dkrh||k}	nz|dkrz||k}	nh|dkrŒ||k}	nV|dkrž||k}	nD|dkrÐ|s¶dd	d
œW S ||  koÈ|kn  }	ndd|› d
œW S |	dd
œW S  ty& }
 z ddt|
ƒ› d
œW  Y d}
~
S d}
~
0 0 dS )u  
        Valida una comparaciÃ³n segÃºn el operador y tipo de dato.
        
        Args:
            operator (str): Operador (>, <, >=, <=, =, !=, BETWEEN)
            valor_actual: Valor actual a validar
            valor_esperado: Valor esperado de la regla
            valor_esperado2: Segundo valor esperado (para BETWEEN)
            value_type (str): Tipo de dato (Number, Date)
            
        Returns:
            dict: {
                'valido': bool,
                'detalle': str (opcional)
            }
        ZBETWEENú>ú<z>=z<=ú=z!=Fz$Operador BETWEEN requiere RuleValue2)r   ZdetallezOperador no soportado: Nu   Error en validaciÃ³n: )Ú_convertir_tipoÚ	ExceptionÚstr)r	   r   r   r   r   r   Zvalor_actual_convertidoZvalor_esperado_convertidoZvalor_esperado2_convertidor   Úer
   r
   r   r#   æ   sB    





þþþþz#RulesValidator._validar_comparacionc                 C   st  |du rdS z|dkrŠt |ttfƒr0t|ƒW S t |tƒr€| ¡  ¡ }| dd¡ dd¡}| dd¡ dd¡}| ¡ }t|ƒW S t|ƒW S |dkrt |ttfƒrºt |tƒr°|n| ¡ W S t |tƒrg d	¢}|D ]6}zt 	||¡ ¡ W   W S  t
y   Y qÒY qÒ0 qÒt
d
|› ƒ‚|W S t|ƒW S W nD tyn } z*t
d|› d|› dt|ƒ› ƒ‚W Y d}~n
d}~0 0 dS )a[  
        Convierte un valor al tipo de dato correcto.
        
        Args:
            valor: Valor a convertir
            value_type (str): Tipo de dato ('Number', 'Date')
            
        Returns:
            Valor convertido (int, float, date, o str)
            
        Raises:
            ValueError: Si no se puede convertir
        NÚNumberÚkmÚ Zkgu   dÃ­asZdiasÚDate)ú%Y-%m-%dz%d/%m/%Yz%d-%m-%Yz%Y/%m/%dzNo se pudo parsear fecha: zError al convertir 'z
' a tipo 'z': )Ú
isinstanceÚintÚfloatr6   ÚstripÚlowerÚreplacer   r   ÚstrptimeÚ
ValueErrorr5   )r	   r/   r   Zvalor_limpioZformatosZformator7   r
   r
   r   r4   ,  s8    




zRulesValidator._convertir_tipoc                 C   s
   | j  ¡ S )u¸   
        Obtiene todas las reglas activas del sistema.
        Ãštil para debugging o administraciÃ³n.
        
        Returns:
            dict: Resultado de la consulta SQL
        )r   Zobtener_todas_reglas_activasr   r
   r
   r   Úobtener_todas_reglasr  s    z#RulesValidator.obtener_todas_reglasc                 C   s   | j  |¡}|d o|d S )uÔ   
        Verifica si una regla existe y estÃ¡ activa.
        
        Args:
            rule_code (str): CÃ³digo de la regla
            
        Returns:
            bool: True si existe y estÃ¡ activa
        r   Úexiste)r   Zverificar_existencia_regla)r	   r)   Ú	resultador
   r
   r   Úverificar_regla_existe|  s    
z%RulesValidator.verificar_regla_existeN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r,   r0   r#   r4   rE   rH   r
   r
   r
   r   r      s   t8FF
r   é,  c                 C   sV   z:t | ƒ}||krdddœW S dd|› d|› ddœW S W n   dddœ Y S 0 dS )	u  
    Valida que el kilometraje sea mayor o igual al mÃ­nimo establecido.
    
    Args:
        kilometraje (float): Kilometraje del viaje
        km_minimo (float): Kilometraje mÃ­nimo requerido (default: 300)
        
    Returns:
        dict: {'valido': bool, 'mensaje': str}
    TNr-   Fz$El kilometraje debe ser de al menos z km. Actual: z kmu   Kilometraje invÃ¡lido)r?   )ÚkilometrajeZ	km_minimor9   r
   r
   r   Úvalidar_kilometraje_minimoŽ  s    þþþrO   é   c                 C   sž   z‚t | tƒrt | d¡ ¡ }nt | tƒr2|  ¡ }n| }t ¡ t|d }||kr\dddœW S || j}dd|› d|› d	dœW S W n   dd
dœ Y S 0 dS )u*  
    Valida que la fecha de salida tenga la anticipaciÃ³n requerida.
    
    Args:
        fecha_salida (str o date): Fecha de salida del viaje
        dias_anticipacion (int): DÃ­as de anticipaciÃ³n requeridos (default: 7)
        
    Returns:
        dict: {'valido': bool, 'mensaje': str}
    r<   )ÚdaysTNr-   Fz%Debe solicitar el vuelo con al menos u     dÃ­as de anticipaciÃ³n. Faltan u    dÃ­asu   Fecha de salida invÃ¡lida)r=   r6   r   rC   r   Útodayr   rQ   )Úfecha_salidaÚdias_anticipacionÚfechaZfecha_minimaZdias_faltantesr
   r
   r   Úvalidar_anticipacion_dias¬  s&    


þ
þþrV   c                 C   sv   zZg }| dkr|  d¡ |dur:|dkr:|  d|› d¡ |rPdd |¡d	œW S d
dd	œW S    ddd	œ Y S 0 dS )u‘  
    Valida que el equipaje cumpla con los lÃ­mites establecidos.
    
    Reglas:
    - MÃ¡ximo 1 maleta documentada
    - Peso mÃ¡ximo por maleta: 23 kg
    - Equipaje de mano: 10 kg
    
    Args:
        cantidad_maletas (int): Cantidad de maletas documentadas
        exceso_kg (float): Exceso de equipaje en kg (opcional)
        
    Returns:
        dict: {'valido': bool, 'mensaje': str}
    r   u&   MÃ¡ximo 1 maleta documentada permitidaNé   u-   El peso mÃ¡ximo por maleta es 23 kg. Actual: z kgFz; r-   Tu   Datos de equipaje invÃ¡lidos)r$   Újoin)Zcantidad_maletasZ	exceso_kgr   r
   r
   r   Úvalidar_equipaje_pasajeroÔ  s"    
þþþrY   )rM   )rP   )N)rL   ÚsysÚosr   r   r   Úpathr$   ÚdirnameÚabspathÚ__file__Z&Consultas_SQL.Utilities.RulesGlobalSQLr   r   rO   rV   rY   r
   r
   r
   r   Ú<module>   s   ,  r

(