o
    h\l                     @   s  d dl mZmZmZmZ d dlmZ d dlmZ d dlZd dl	Z	d dl
Z
d dlZd dlZejejd eeZeeZdejd< dejd	< d
ejd< dZe	jdZeeZG dd dejZG dd dejZG dd dejZdLddZdd Zdd Zdd Z dd Z!dd Z"d d! Z#d"d# Z$d$d% Z%d&d' Z&ej'd(d)gd*d+d, Z(e'd-d.d/ Z)e'd0d1d2 Z*e'd3d4d5 Z+e'd6d7d8 Z,e'd9d:d; Z-e'd<d=d> Z.ej'd?d)gd*d@dA Z/e'dBdCdD Z0dEdF Z1e1  edGkrej2dHdIdJdK dS dS )M    )Flaskrequestjsonifyrender_template)
SQLAlchemy)datetimeN)levelzmssql+pyodbc://sa:Sistemas123*%2F@194.163.45.32:1433/RappiWebhooks?driver=ODBC+Driver+17+for+SQL+Server&TrustServerCertificate=yes&Encrypt=yes&timeout=30SQLALCHEMY_DATABASE_URIFSQLALCHEMY_TRACK_MODIFICATIONSwebhooks_secret_2025
SECRET_KEYzhttps://cierresmig.onlineRAPPI_WEBHOOK_SECRETc                   @   s   e Zd ZdZejejddZejedddZ	eedZ
eedZeedZejejddZejejejdZeed	ZejejddZejejddZeejZd
S )WebhookEventWebhookEventsTprimary_key2   Fnullabled   default-   N)__name__
__module____qualname____tablename__dbColumnIntegeridStringevento_tipoorder_idstore_id
event_nameText
datos_jsonDateTimer   utcnowfecha_recepcion	ip_origenBooleanfirma_valida	procesadoerror_procesamiento r0   r0   /var/www/html/Webhooks/app.pyr   #   s    r   c                   @   s   e Zd ZdZejejddZeejedZ	eje
dddZee
dZee
dZee
dZee
dZee
d	ZeejZeejZejejejd
ZdS )RappiEventDetailRappiEventDetailsTr   zWebhookEvents.idr   Fr   r     r   N)r   r   r   r   r   r   r   r    
ForeignKeywebhook_event_idr!   
event_typer#   r$   r%   
event_timemessager&   courier_dataadditional_infor(   r   r)   fecha_procesamientor0   r0   r0   r1   r2   2   s    r2   c                   @   s~   e Zd ZdZejejddZejedddZ	eej
ZeedZeedZejejejdZeej
Zd	S )
	SystemLog
SystemLogsTr      INFOr   r   r   N)r   r   r   r   r   r   r   r    r!   r   r&   r9   endpoint
ip_addressr(   r   r)   	timestampadditional_datar0   r0   r0   r1   r=   A   s    r=   c              
   C   s   z.t | ||tr
tjnd|rt|ndd}tj| tj  t	
d|  d|  W dS  tyI } zt	d|  W Y d}~dS d}~ww )zRegistrar eventos del sistemaN)r   r9   rA   rB   rD   [z] zError logging system event: )r=   r   remote_addrjsondumpsr   sessionaddcommitloggerinfo	Exceptionerror)r   r9   rA   rD   	log_entryer0   r0   r1   log_system_eventN   s   
rR   c              
   C   s   t r|sdS zH|d}d}d}|D ]}|dd\}}|dkr#|}q|dkr)|}q|r.|s1W dS | d|  }tt d	|d	tj }	t||	W S  t	yi }
 zt
d
|
  W Y d}
~
dS d}
~
ww )z,Validar la firma de Rappi usando HMAC SHA256F,N=   tsign.zutf-8zError validating signature: )r   splithmacnewencodehashlibsha256	hexdigestcompare_digestrN   rL   rO   )payload_bodysignature_headerpartsrC   	signaturepartkeyvaluesigned_payloadexpected_signaturerQ   r0   r0   r1   validate_rappi_signature_   s:   
rj   c              
   C   s  zt d|   d| v rt| dkrt d W dS d| v r?d| v r?| dd }d|v r7t d	 W d
S t d W dS d| v rUd| vrUt| dkrUt d W dS d| v r}d| v r}d| v r}| dd }d|v rut d W dS t d W dS d| v rd| v rd| v rd| v rt d W dS d| v rd| v rt d W dS d| v rd| v rd| v rd| v rt d W d S t d!t|    W d"S  ty } zt 	d#|  W Y d$}~d"S d$}~ww )%uE   Identificar el tipo de evento basándose en la estructura del payloadz"Identificando evento con payload: r$   rU   zEvento identificado como PINGPINGr9    approvedz&Evento identificado como MENU_APPROVEDMENU_APPROVEDz4Evento identificado como MENU_REJECTED (con mensaje)MENU_REJECTEDz4Evento identificado como MENU_REJECTED (sin mensaje)r#   eventcancelz+Evento identificado como ORDER_EVENT_CANCELORDER_EVENT_CANCELz6Evento identificado como ORDER_OTHER_EVENT (por event)ORDER_OTHER_EVENTr8   additional_informationz5Evento identificado como ORDER_OTHER_EVENT (completo)external_store_idenabledz+Evento identificado como STORE_CONNECTIVITYSTORE_CONNECTIVITYlatlngeta_in_millisz*Evento identificado como ORDER_RT_TRACKINGORDER_RT_TRACKINGz0No se pudo identificar el tipo de evento. Keys: UNKNOWNz$Error identificando tipo de evento: N)
rL   rM   lengetlowerwarninglistkeysrN   rO   )webhook_datar9   r%   rQ   r0   r0   r1   identify_event_type   sP   








r   c              
   C   s   z3|  d}|  d}|  d}|stdtd|||d}tj| tdd| ||d	d
 W dS  tyH } z	t	d|   d}~ww )z"Procesar evento ORDER_EVENT_CANCELr#   r$   rp   zNo se pudo obtener order_idrr   )r7   r#   r$   r%   r@   u   Cancelación procesada: )rp   r$   rD   Tz%Error processing ORDER_EVENT_CANCEL: N)
r~   
ValueErrorr2   r   rI   rJ   rR   rN   rL   rO   )r   r#   r$   r%   event_detailrQ   r0   r0   r1   process_order_event_cancel   s,   


r   c           	   
   C   s   zH|  d}|  d}|  d}|  d}|  di }| d}td|||||r-t|ndt|d	}tj| td
d| d|  W dS  ty] } z	t	
d|   d}~ww )z!Procesar evento ORDER_OTHER_EVENTr#   r$   rp   r8   rt   r:   rs   N)r7   r#   r$   r%   r8   r:   r;   r@   zEvento de orden procesado: z - Tz$Error processing ORDER_OTHER_EVENT: r~   r2   rG   rH   r   rI   rJ   rR   rN   rL   rO   )	r   r#   r$   r%   r8   rt   r:   r   rQ   r0   r0   r1   process_order_other_event   s0   





r   c              
   C   sp   z"|  d}|  d}td||d}tj| tdd|  W dS  ty7 } z	td|   d	}~ww )
zProcesar evento MENU_APPROVEDr$   r9   rn   )r7   r$   r9   r@   u   Menú aprobado para tienda: Tz Error processing MENU_APPROVED: N	r~   r2   r   rI   rJ   rR   rN   rL   rO   )r   r$   r9   r   rQ   r0   r0   r1   process_menu_approved   s    

r   c              
   C   d   z|  d}td|d}tj| tdd|  W dS  ty1 } z	td|   d}~ww )	zProcesar evento MENU_REJECTEDr$   ro   r7   r$   r@   u   Menú rechazado para tienda: Tz Error processing MENU_REJECTED: Nr   r   r$   r   rQ   r0   r0   r1   process_menu_rejected     
r   c              
   C   r   )	zProcesar evento PINGr$   rk   r   r@   zPing recibido para tienda: TzError processing PING: Nr   r   r0   r0   r1   process_ping"  r   r   c              
   C   s   z6|  d}|  d}|  d}td||td|id}tj| |r'dnd}tdd	| d
|  W dS  tyK } z	t	
d|   d}~ww )z"Procesar evento STORE_CONNECTIVITYru   rv   r9   rw   )r7   r$   r9   r;   
habilitadadeshabilitadar@   zTienda  Tz%Error processing STORE_CONNECTIVITY: Nr   )r   r$   rv   r9   r   statusrQ   r0   r0   r1   process_store_connectivity6  s&   


r   c              
   C   s   zL|  d}|  d}|  d}|  d|  d|  d|  d|  dd	}td
t|t|t|td|id}tj| tdd|  W dS  t	ya } z	t
d|   d}~ww )z!Procesar evento ORDER_RT_TRACKINGr#   r$   
courier_idrx   ry   rz   eta_type
created_at)rx   ry   rz   r   r   r{   )r7   r#   r$   r;   r:   r@   z!Tracking actualizado para orden: Tz$Error processing ORDER_RT_TRACKING: N)r~   r2   strrG   rH   r   rI   rJ   rR   rN   rL   rO   )r   r#   r$   r   tracking_infor   rQ   r0   r0   r1   process_order_rt_trackingO  s2   


r   /webhook/rappiPOST)methodsc               
   C   sx  zt jdd} t jd}t jdd}tdddd	t|id
 d}tr<t| |}|s<tdddd tddidfW S zt 	 }|sGt
dW n% tym } ztdd| dd tddidfW  Y d}~W S d}~ww t|}tdd| dt| id d}d}d}	|dv r|d}|d}|d}	n(|dv r|d}n|dkr|d}n|d krt|dd!}t|dd!}t||||	| t j|d"}
zo|d#krt| d|
_na|d$krt| d|
_nU|d%krt| d|
_nI|d&krt| d|
_n<|d'krt| d|
_n/|dkrt| d|
_n"|d kr)t| d|
_nd(|
_d)| |
_td*d)| d+|id W n& tye } zd(|
_t||
_tdd,| d-|  W Y d}~nd}~ww tj|
 tj  |d'kr~td.d/d0W S tdd1|
j|dd2d3fW S  ty } z#t !d4|  tdd4| dd td5t|d6d7fW  Y d}~S d}~ww )8z1Endpoint principal para recibir webhooks de RappiT)as_textzRappi-SignaturezX-Rappi-Event-Typeunknownr@   zWebhook recibido desde Rappir   has_signature)rA   rD   ERRORu   Firma de webhook inválida)rA   rO   zInvalid signaturei  zEmpty JSON bodyu   JSON inválido en webhook: zInvalid JSON  NzEvento identificado como: payload_keysr   )rr   rs   r#   r$   rp   )rn   ro   rk   rw   ru   r{   rl   )r"   r#   r$   r%   r'   r+   r-   rr   rs   rn   ro   rk   FzTipo de evento no reconocido: WARNINGpayloadzError procesando webhook z: OKz!Sistema funcionando correctamente)r   descriptionzWebhook procesado correctamente)successr9   event_idr7   identified_from_payload   zError general en webhook: zError interno del servidor)rO   r9   r4   )"r   get_dataheadersr~   rR   boolr   rj   r   get_jsonr   rN   r   r   r   r   r   rF   r   r.   r   r   r   r   r   r   r/   r   rI   rJ   rK   r    rL   rO   )ra   rb   event_type_from_headersignature_validr   rQ   r7   r#   r$   r%   webhook_eventprocess_errorr0   r0   r1   webhook_rappir  s   








"


r   /c                   C   s   t dt ddS )u   Página principalz
index.htmlr   )webhook_url)r   WEBHOOK_BASE_URLr0   r0   r0   r1   home  s   r   z/api/eventosc                  C   s   zRt jjddtd} t jjddtd}tjtj j	| |dd}g }|j
D ]}||j|j|j|j|j|jd|j|j|j|jd	
 q't||j|j| d
W S  tyv } ztd|  tdt|idfW  Y d}~S d}~ww )zObtener eventos de webhookspagerU   typeper_pager   Fr   r   	error_out%Y-%m-%d %H:%M:%S)
r    tipor#   r$   r%   fechaipr-   r.   rO   )eventostotalpagescurrent_pagezError obteniendo eventos: rO   r4   N)r   argsr~   intr   queryorder_byr*   descpaginateitemsappendr    r"   r#   r$   r%   strftimer+   r-   r.   r/   r   r   r   rN   rL   rO   r   )r   r   r   resulteventorQ   r0   r0   r1   get_eventos  sB   



 r   z/api/event-detailsc                  C   s
  z`t jjddtd} t jjddtd}t jd}tj}|r&|tj|k}|tj	
 j| |dd}g }|jD ]}||j|j|j|j|j|j|j|j	d	d
 q9t||j|j| dW S  ty } ztd|  tdt|idfW  Y d}~S d}~ww )z&Obtener detalles de eventos procesadosr   rU   r   r   r   r7   Fr   r   )r    r7   r#   r$   r%   r8   r9   r<   )detailsr   r   r   zError obteniendo detalles: rO   r4   N)r   r   r~   r   r2   r   filterr7   r   r<   r   r   r   r   r    r#   r$   r%   r8   r9   r   r   r   r   rN   rL   rO   r   )r   r   r7   r   r   r   detailrQ   r0   r0   r1   get_event_details&  sF   



 r   z/api/estadisticasc               
   C   s   zCt j } tj }i }dD ]}t jj|d }|||< qt jt j  }t	| |||r9|j
|j dnddt ddW S  tyg } ztd|  t	d	t|id
fW  Y d}~S d}~ww )u!   Obtener estadísticas del sistemarr   rs   rn   ro   rk   rw   r{   )r"   )r   r   NTr   )total_eventostotal_detalles_procesadoseventos_por_tipoultimo_eventosistema_activor   u    Error obteniendo estadísticas: rO   r4   )r   r   countr2   	filter_byr   r*   r   firstr   r"   	isoformatr   rN   rL   rO   r   )r   total_detallesr   r7   r   r   rQ   r0   r0   r1   get_estadisticasN  s<   



 r   z/healthc               
   C   s   z*t jt d} |  }|r'|d dkr'tdt  t	 dddW S t
d t
yU } ztd	|  td
t|t  dddfW  Y d}~S d}~ww )zHealth check para monitoreozSELECT 1 as testr   rU   healthyr   	connected)r   rC   r   databasezDatabase test failedzHealth check failed: 	unhealthydisconnected)r   rO   rC   r   r4   N)r   rI   executetextfetchoner   r   r)   r   r   rN   rL   rO   r   )
test_queryr   rQ   r0   r0   r1   health_checkp  s.   


r   z/debug/last-requestsc                  C   sV  zt jt jdkt j d } g }| D ]+}i }|j	r2zt
|j	}W n	   d|j	i}Y ||jd|j|j|j|d qtjtj d }g }|D ]'}||j|j|j|j|jdt|jdkrx|jdd d	 n|jd
 qWt||tj t ddW S  ty } ztdt|idfW  Y d}~S d}~ww )u7   Endpoint para debug - ver últimas peticiones recibidasr   
   rawr   )rC   r   r9   r   rD      r4   Nz...)r    r   r$   r.   r   r'   )logswebhookstotal_webhooksr   rO   )r=   r   r   rA   r   rC   r   limitallrD   rG   loadsr   r   r   r9   rB   r   r*   r    r"   r$   r.   r}   r'   r   r   r   rN   r   )r   r   logrD   r   r   whrQ   r0   r0   r1   debug_last_requests  sT   

	
$
	
 r   z/test-webhook-manualc               
   C   s|   z!t  } | stddidfW S t| }td|t|  | dW S  ty= } ztdt|idfW  Y d}~S d}~ww )u>   Endpoint para probar manualmente la identificación de eventosrO   zNo JSON data providedr   T)r   identified_event_typer   r   r4   N)r   r   r   r   r   r   rN   r   )	test_datar7   rQ   r0   r0   r1   test_webhook_manual  s   

 r   z/configc                   C   s    t t dttdg ddS )u   Mostrar configuración actualr   Tr   )r   
has_secretdatabase_connectedsupported_events)r   r   r   r   r0   r0   r0   r1   show_config  s   r  c               
   C   s   z.t   t  td tdddt did W d   W dS 1 s'w   Y  W dS  tyC }  z	t	d|    d} ~ ww )	zInicializar base de datosz(Base de datos inicializada correctamenter@   zSistema de webhooks iniciador   r   r   Nz#Error inicializando base de datos: )
appapp_contextr   
create_allrL   rM   rR   r   rN   rO   )rQ   r0   r0   r1   init_database  s   

&r  __main__z0.0.0.0i  T)hostportdebug)NN)3flaskr   r   r   r   flask_sqlalchemyr   r   rG   osr]   rZ   loggingbasicConfigr@   	getLoggerr   rL   r  configr   environr~   r   r   Modelr   r2   r=   rR   rj   r   r   r   r   r   r   r   r   router   r   r   r   r   r   r   r   r  r  runr0   r0   r0   r1   <module>   sn   



"<#
 


$
'
!

1


