U
    —âñj^b ã                   @   s  d Z ddgZddlZddlZddlZddlZddlZddlZddlmZm	Z	m
Z
 ddlmZ ddlmZ ddlmZmZ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mZ ddlmZ ddlm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z) ddl*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2 ddl3m4Z4m5Z5 ddl6m7Z7m8Z8m9Z9m:Z:m;Z; ddl<m=Z= ddl>m?Z? ddl@mAZA dZBdZCeC�ršddlmDZDmEZEmFZFmGZGmHZH ddlImJZJ ddlKmLZL ddlMmNZN ddlOmPZP ddlQmRZRmSZSmTZTmUZU ddlVmWZW ddlXmYZYmZZZm[Z[m\Z\m]Z]m^Z^ ddl_m`Z` ddlambZb dd lcmdZd dd!lemfZf dd"lgmhZh dd#limjZjmkZkmlZlmmZmmnZn dd$lompZpmqZqmrZr dd%lsmtZtmuZumvZvmwZwmxZxmyZymzZz �nLddlmDZDmEZEmFZFmGZGmHZH ddlImJZJ ddlKmLZL ddlMmNZN ddlOmPZP ddlQmRZRmSZSmTZTmUZU ddlVmWZW ddlXmYZYmZZZm[Z[m\Z\m]Z]m^Z^ dd&l{m|Z|m}Z}m~Z~mZ ddl_m`Z` ddlambZb dd lcmdZd dd!lemfZf dd"lgmhZh dd#limjZjmkZkmlZlmmZmmnZn dd$lompZpmqZqmrZr dd%lsmtZtmuZumvZvmwZwmxZxmyZymzZz dd'l€m�Z� ddl‚Z‚dd(lƒm„Z„m…Z…m†Z†m‡Z‡mˆZˆ d)d*d+d,d-gZ‰d.ZŠd/Z‹d0ZŒd1Z�d2ZŽd3Z�d4Z�d5gZ‘G d6d7„ d7ƒZ’e’ƒ Z“e e”d8d9�Z•d:d;d<d=d>d?d@dAdBdCdDdEgZ–ee•e–dFdGdHdIdJdKgdL� dMe•j—dN< dOe•j—dP< e	dQdR�e•j—dS< e	dTdU�e•j—dV< dWdXge•j—dY< de•j—dZ< de•j—d[< dFe•j—d\< d]e•j—d^< de•j—d_< e+e•ƒZ˜e)d`e”ƒZ™eHƒ  e˜jšdadb„ ƒZ›e™jœdcdd„ ƒZ�e™jždedf„ ƒZŸdgdh„ Z diZ¡e¢dje¡› �ƒ ej£ ¤e¡dk¡Z¥e e¥ƒ dldm„ Z¦dndo„ Z§dpdq„ Z¨drds„ Z©dtdu„ Zªdvdw„ Z«dxdy„ Z¬dzd{„ Z­d|d}„ Z®d~d„ Z¯d€dq„ 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¸d“d”„ Z¹d•d–„ Zºd—d˜„ Z»d™dš„ Z¼�d€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Å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Î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×dÑdÒ„ ZØe•jÙddÓdÔidÕ�e• ÙdÖ¡d×dØ„ ƒƒZÚe™jÙdÙdÚgdÛ�dÜdÝ„ ƒZÛe•jÙdÞdGgdÛ�dßdà„ ƒZÜe™jÙdádHgdÛ�dâdã„ ƒZÝe™jÙdädGgdÛ�e/ƒ dådæ„ ƒƒZÞe™jÙdçdHgdÛ�e/dFdè�dédê„ ƒƒZße™jÙdëdHgdÛ�e/dFdè�dìdí„ ƒƒZàe™jÙdîdHgdÛ�dïdð„ ƒZáe™jÙdñdHgdÛ�e/ƒ dòdó„ ƒƒZâe™jÙdôdGgdÛ�dõdö„ ƒZã�d�dødù„Zädúdû„ Zåe™jÙdüdGgdÛ�dýdþ„ ƒZæe™jÙdÿdGgdÛ��d �d„ ƒZçe™jÙ�ddGdHgdÛ��d�d„ ƒZèe™jÙ�ddHgdÛ��d�d„ ƒZée™jÙ�ddHgdÛ��d	�d
„ ƒZêe™jÙ�ddHgdÛ��d�d„ ƒZëe™jÙ�ddHgdÛ��d�d„ ƒZìe™jÙ�ddGgdÛ��d�d„ ƒZíe™jÙ�ddHgdÛ��d�d„ ƒZîe™jÙ�ddHgdÛ��d�d„ ƒZïe™jÙ�ddHgdÛ�e/ƒ �d�d„ ƒƒZðe™jÙ�ddJgdÛ��d�d„ ƒZñe™jÙ�d dGgdÛ��d!�d"„ ƒZòe™jÙ�d#dHgdÛ�e/ƒ �d$�d%„ ƒƒZóe™jÙ�d&dGgdÛ�e/ƒ �d'�d(„ ƒƒZôe™jÙ�d)dHgdÛ��d*�d+„ ƒZõe™jÙ�d,dHgdÛ��d-�d.„ ƒZöe™jÙ�d/dHgdÛ��d0�d1„ ƒZ÷e™jÙ�d2dGgdÛ��d3�d4„ ƒZøe™jÙ�d5dHgdÛ��d6�d7„ ƒZùe™jÙ�d8dGgdÛ�e/ƒ �d9�d:„ ƒƒZúe™jÙ�d;dHgdÛ�e/ƒ �d<�d=„ ƒƒZû�d>�d?„ Züe™jÙ�d@dHgdÛ�e/ƒ �dA�dB„ ƒƒZýe™jÙ�dCdGgdÛ�e/ƒ �dD�dE„ ƒƒZþe™jÙ�dFdHgdÛ�e/ƒ �dG�dH„ ƒƒZÿe™jÙ�dIdHgdÛ�e/ƒ �dJ�dK„ ƒƒ�Z �dL�dM„ �Z�dN�dO„ �Z�dP�dQ„ �Z�dR�dS„ �Z�dT�dU„ �Z�dV�dW„ �Z�dX�dY„ �Z�dZ�d[„ �Z�d\�d]„ �Z	�d^�d_„ �Z
�d`�da„ �Z�db�dc„ �Z�dd�de„ �Z�df�dg„ �Z�dh�di„ �Z�dj�dk„ �Z�dl�dm„ �Z�dn�do„ �Z�dp�dq„ �Z�dr�ds„ �Z�dt�du„ �Z�dv�dw„ �Z�dx�dy„ �Z�dz�d{„ �Z�d|�d}„ �Z�d~�d„ �Z�d€�d�„ �Z�d‚�dƒ„ �Z�d„�d…„ �Z�d†�d‡„ �Z�e�dˆœ�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(�d›�dœ„ �Z)�d��dž„ �Z*�dŸ�d „ �Z+�d¡�d¢„ �Z,�d‚�d¥�d¦„�Z-�d§�d¨„ �Z.�d©�dª„ �Z/�d«�d¬„ �Z0�d­�d®„ �Z1�d¯�d°„ �Z2�d±�d²„ �Z3�d³�d´„ �Z4�dµ�d¶„ �Z5�d·�d¸„ �Z6�d¹�dº„ �Z7�dƒ�d¼�d½„�Z8�d„�d¾�d¿„�Z9�dÀ�dÁ„ �Z:�dÂ�dÃ„ �Z;�dÄ�dÅ„ �Z<�dÆ�dÇ„ �Z=�dÈ�dÉ„ �Z>e™jÙ�dÊdGgdÛ��dË�dÌ„ ƒ�Z?e™jÙ�dÍdHgdÛ��dÎ�dÏ„ ƒ�Z@e™jÙ�dÐdGgdÛ��dÑ�dÒ„ ƒ�ZAe™jÙ�dÓdHgdÛ��dÔ�dÕ„ ƒ�ZBe™jÙ�dÖdHgdÛ��d×�dØ„ ƒ�ZCe™jÙ�dÙdHgdÛ��dÚ�dÛ„ ƒ�ZDe™jÙ�dÜdGgdÛ��dÝ�dÞ„ ƒ�ZEe™jÙ�dßdHgdÛ��dà�dá„ ƒ�ZF�d…�dã�dä„�ZGe™jÙ�dådHgdÛ��dæ�dç„ ƒ�ZHe™jÙ�dèdHgdÛ��dé�dê„ ƒ�ZIe™jÙ�dëdHgdÛ�e/ƒ �dì�dí„ ƒƒ�ZJe™jÙ�dîdGgdÛ��dï�dð„ ƒ�ZKe™jÙ�dñdHgdÛ��dò�dó„ ƒ�ZLe™jÙ�dôdHgdÛ��dõ�dö„ ƒ�ZMe™jÙ�d÷dGgdÛ�e/ƒ �dø�dù„ ƒƒ�ZNe™jÙ�dúdGgdÛ�e/ƒ �dû�dü„ ƒƒ�ZOe™jÙ�dýdGgdÛ��dþ�dÿ„ ƒ�ZPe™jÙ�d dGgdÛ�e/ƒ �e�dœ�d�d„ƒƒ�ZQe™jÙ�ddHgdÛ��d�d„ ƒ�ZRe™jÙ�ddGgdÛ��d�d	„ ƒ�ZSe™jÙ�d
dGgdÛ��d�d„ ƒ�ZTe™jÙ�ddHgdÛ��d�d„ ƒ�ZU�d�d„ �ZVe™jÙ�ddHgdÛ��d�d„ ƒ�ZWe™jÙ�ddHgdÛ��d�d„ ƒ�ZXe™jÙ�ddGgdÛ��d�d„ ƒ�ZYe™jÙ�ddGgdÛ��d�d„ ƒ�ZZe�dœ�d�d „�Z[�ee�d!œ�d"�d#„�Z\�d†�ee�d!œ�d$�d%„�Z]dd�d&œ�d'�d(„�Z^�d)�d*„ �Z_e™jÙ�d+dGgdÛ��d,�d-„ ƒ�Z`e™jÙ�d.dGgdÛ��d/�d0„ ƒ�Zae™jÙ�d1dGgdÛ�e/ƒ �d2�d3„ ƒƒ�Zb�d4�d5„ �Zc�d6�d7„ �Zde™jÙ�d8dGgdÛ��d9�d:„ ƒ�Ze�d;�d<„ �Zfe™jÙ�d=dGgdÛ��d>�d?„ ƒ�Zge™jÙ�d@dGgdÛ��dA�dB„ ƒ�Zhe™jÙ�dCdGgdÛ��dD�dE„ ƒ�Zie™jÙ�dFdGgdÛ��dG�dH„ ƒ�Zje™jÙ�dIdGgdÛ��dJ�dK„ ƒ�Zke™jÙ�dLdGgdÛ��dM�dN„ ƒ�Zle™jÙ�dOdGgdÛ��dP�dQ„ ƒ�Zme™jÙ�dRdGgdÛ��dS�dT„ ƒ�Zn�dU�dV„ �Zoe™jÙ�dWdHgdÛ��dX�dY„ ƒ�Zpe™jÙ�dZdGgdÛ��d[�d\„ ƒ�Zqe™jÙ�d]dGgdÛ��d^�d_„ ƒ�Zre™jÙ�d`dGgdÛ��da�db„ ƒ�Zse™jÙ�dcdGgdÛ��dd�de„ ƒ�Zte™jÙ�dfdGgdÛ��dg�dh„ ƒ�Zue™jÙ�didGgdÛ��dj�dk„ ƒ�Zv�dl�dm„ �Zwe•�jx�d‡�dn�do„ƒ�Zye•�jz�dˆ�dp�dq„ƒ�Z{e¢�drƒ e¢�ds�e|eJƒ› �ƒ e¢�dt�e}eJ�j~ƒ› �ƒ eeËƒ e•� e¡ e•� eJ¡ e•� eL¡ e•�je™eB�du� e”�dvk�rd�Z€�dw�Z��dx�Z‚e¢�dyƒ e¢�dzƒ d�Zƒe•�j„� …¡ D ]6�Z†e¢�d{�e†› �d|�e†�j‡› �ƒ �eƒ�d£7 �Zƒ�q�e¢�d}�eƒ› �ƒ e¢�d~ƒ e•� ˆ¡ �$ e•�j‰�e��e‚�e€dFdF�d� W 5 Q R X dS (‰  uc  
===============================================================================
 Archivo:        Main service manager.py
 Autor:           (TU_EMPRESA)
 Fecha creaciÃ³n: AAAA-MM-DD
 VersiÃ³n:        VERSIÃ“N_INICIAL_BLUEPRINT_LEGACY_MIGRATION
===============================================================================
 DescripciÃ³n:
    Breve descripciÃ³n del propÃ³sito del archivo y su funcionalidad

===============================================================================
 Copyright:
    Â© AÃ‘O TU_EMPRESA. Todos los derechos reservados.
    Este archivo forma parte de NOMBRE_PROYECTO y se distribuye bajo
    los tÃ©rminos de la licencia TIPO_LICENCIA.

===============================================================================
 Interface Change List:
    VersiÃ³n     Fecha        Autor                DescripciÃ³n del cambio
    ---------   ----------   ------------------   ---------------------------
    vX.X.X    AAAA-MM-DD TU_NOMBRE   DescripciÃ³n breve
    vX.X.X    AAAA-MM-DD TU_NOMBRE   DescripciÃ³n breve
===============================================================================
ZExampleClassÚmainé    N)ÚdatetimeÚ	timedeltaÚtimezone)Úpprint)Údefaultdict)Úencolar_dato_recibidoÚcampos_reservadosÚsin_pendientesÚbloqueo_automaticosÚcompletar_altaÚ
configurar)Úlog_centros)Úetiquetas_bp)ÚCORS)Úparser)
ÚFlaskÚgÚjsonifyÚrequestÚsend_from_directoryÚ	send_fileÚafter_this_requestÚmake_responseÚurl_forÚ	Blueprint)Ú
JWTManagerÚcreate_access_tokenÚcreate_refresh_tokenÚget_jwt_identityÚjwt_requiredÚset_access_cookiesÚset_refresh_cookiesÚdecode_token)Úcheck_password_hashÚgenerate_password_hash)ÚMongoClientÚ	UpdateOneÚ	InsertOneÚerrorsÚ
ReplaceOne)ÚBulkWriteError)ÚObjectId)Ú	json_utilú/F)Úget_dbÚSERVICES_DB_MAPÚinsert_log_in_user_historyÚensure_analytic_collectionÚensure_analytic_indexes)Únotifications_bp)Úagent_data_bp)Úcheck_legacy_expiration)Úsend_automatic_email)Úupdate_emailsÚdelete_contact_listÚOP_SETÚfetch_emails_by_location)Úconsolidado_empresa)Útipo_de_datosÚprocess_sensor_dataÚget_historial_controlÚget_generatorÚget_control_by_centro_idÚ get_control_version_by_centro_id)Úget_latest_data_ts)Úget_latest_comap_timestamp)Úgen_data_report)Ú_gen_data_report)Ú(verificacion_status_servicios_por_centro)Úcompute_daily_analytic_dataÚcompute_multiple_analytic_daysÚcompute_analytic_area_dataÚ!compute_analytic_area_versus_dataÚcompute_analytics_by_region)Úbuild_centro_idÚnormalize_area_idÚnormalize_centro_id)ÚFEEDER_SCORE_COLLECTION_NAMEÚcompute_feeder_score_by_areaÚcompute_feeder_score_by_regionÚfetch_feeder_score_dataÚ!get_last_feeder_score_received_atÚsave_feeder_score_payloadÚ+validate_and_normalize_feeder_score_payload)Úsave_flux_batchÚsave_flux_singleÚget_flux_historical_dataÚget_flux_heartbeat)Úprocess_flux_day)ÚMAX_NOTES_REQUEST_BYTESÚNOTES_COLLECTION_NAMEÚfetch_notes_for_rangeÚsave_notes_payloadÚ$validate_and_normalize_notes_payloadÚenviroÚnanooxÚscappÚpssÚfluxÚusersÚENVIROZ
NANOOX__TSZScappDBZFLUX__TSÚemailsé2   ÚGerenciac                   @   s,   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	S )
ÚSimpleLoggerc                 C   s   t d|› �ƒ d S )Nz[INFO] ©Úprint©ÚselfÚmsg© rq   ú*/var/www/itgmanager/itgmanager/__init__.pyÚinfoÛ   s    zSimpleLogger.infoc                 C   s   t d|› �ƒ d S )Nz
[WARNING] rl   rn   rq   rq   rr   ÚwarningÞ   s    zSimpleLogger.warningc                 C   s   t d|› �ƒ d S )Nz[ERROR] rl   rn   rq   rq   rr   Úerrorá   s    zSimpleLogger.errorc                 C   s   d S ©Nrq   rn   rq   rq   rr   Údebugä   s    zSimpleLogger.debugN)Ú__name__Ú
__module__Ú__qualname__rs   rt   ru   rw   rq   rq   rq   rr   rk   Ú   s   rk   Úbuild)Ústatic_folderzhttp://localhost:3000zhttps://localhost:3000zhttp://localhost:3001zhttps://localhost:3001zhttp://localhost:8100zhttps://localhost:8100zhttps://localhost:5173zhttp://localhost:5173zhttps://localhostzcapacitor://localhostzionic://localhostzhttps://test.itgchile.comTZGETÚPOSTZOPTIONSZDELETEZPUT)ZoriginsZsupports_credentialsÚmethodszITG-Secret-jwt-keyÚJWT_SECRET_KEYzITG-Secret-reset-keyÚJWT_RESET_SECRET_KEYé   )ZminutesZJWT_ACCESS_TOKEN_EXPIRESé   ©ÚdaysZJWT_REFRESH_TOKEN_EXPIRESÚcookiesÚheadersZJWT_TOKEN_LOCATIONZJWT_ACCESS_COOKIE_PATHZJWT_REFRESH_COOKIE_PATHZJWT_COOKIE_SECUREÚNoneZJWT_COOKIE_SAMESITEZJWT_COOKIE_CSRF_PROTECTZapi_v1c                 C   s`   t ƒ }|t j}|d }| dd¡}|d }|dkr\| d|iddi¡}| pZ| d¡|kS d	S )
zÝ
    Se ejecuta para cualquier token (access o refresh).
    Solo revocaremos aqui los refresh tokens cuyo jti no coincida
    con el ultimo almacenado en la BD. Los access tokens
    los dejamos expirar normalmente.
    ÚjtiÚtypeNÚsubÚrefreshÚusernameÚrefresh_jtié   F)r/   ÚUSER_DATABASE_NAMErf   ÚgetÚfind_one)Z
jwt_headerZjwt_payloadÚclientÚusers_collectionrˆ   Ú
token_typerŒ   Úuserrq   rq   rr   Úcheck_if_token_revoked&  s    
 ÿr–   c                  C   sˆ   t dtj› dtj› �tjd� t dtj d¡› �tjd� t dtj d¡› �tjd� tj} | rvt d| › �tjd� nt d	tjd� d
S )ua   
    Se ejecuta ANTES de procesar la ruta.
    Loguea quÃ© estÃ¡ entrando y si trae cookies.
    z
[DEBUG-ENTRADA] Ruta: z | Metodo: ©Úfilez[DEBUG-ENTRADA] Origin: ÚOriginz[DEBUG-ENTRADA] User-Agent: ú
User-Agentz#[DEBUG-ENTRADA] Cookies recibidas: z=[DEBUG-ENTRADA] PELIGRO: No llegaron cookies en este request.N)	rm   r   ÚpathÚmethodÚsysÚstderrr†   r�   r…   )r…   rq   rq   rr   Úlog_request_infoB  s    rŸ   c                 C   s  t j d¡}|tkr<|| jd< d| jd< d| jd< d| jd< d	| jd
< td| j› �tjd� | j d¡}|rätdtjd� |D ]b}td|› �tjd� d|kr¬tdtjd� d|krÊd|krÊtdtjd� d|kr~tdtjd� q~nt j	 
d¡sþtdtjd� tdtjd� | S )u�   
    Se ejecuta DESPUÃ‰S de cualquier peticiÃ³n (API o Web).
    1. Inyecta seguridad CORS para iOS.
    2. Loguea la respuesta y las cookies salientes.
    r™   zAccess-Control-Allow-OriginÚtruez Access-Control-Allow-Credentialsz<Content-Type, Authorization, X-Requested-With, x-client-typezAccess-Control-Allow-HeaderszGET, POST, OPTIONS, DELETE, PUTzAccess-Control-Allow-Methodsz#no-cache, no-store, must-revalidatezCache-Controlz[DEBUG-SALIDA] Status: r—   z
Set-Cookieu;   [DEBUG-SALIDA] --> FLASK ESTÃ� INTENTANDO ESCRIBIR COOKIES:z    [RAW COOKIE]: zSameSite=Nonez     [ALERTA] Falta SameSite=NoneZSecurez/    [ERROR FATAL] SameSite=None requiere SecurezPath=/z    [ALERTA] Falta Path=/)z.jsz.cssz.pngz.icou0   [DEBUG-SALIDA] NO se detectÃ³ header Set-Cookie.z------------------------------)r   r†   r�   Úallowed_originsrm   Ústatusr�   rž   Zgetlistr›   Úendswith)ÚresponseÚoriginZcookie_headersZcookierq   rq   rr   Úglobal_security_and_loggingT  s.    	




r¦   c              
   C   s^   z"t j| dd� td| › d�ƒ W n6 tk
rX } ztd| › d|› �ƒ W 5 d }~X Y nX d S )NT©Úexist_okzDirectorio 'z ' creado con exito o ya existia.zError al crear el directorio 'ú': )ÚosÚmakedirsrm   Ú	Exception)Zdirectory_pathÚerq   rq   rr   Úcreate_directoryŽ  s
    r®   zvar/www/itgmanager/itgmanagerzDirectorio actual: Úreportesc                 C   s   d}t  || t j¡d k	S )Nz?(android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini))ÚreÚsearchÚ
IGNORECASE)Úuser_agent_strZmobile_regexrq   rq   rr   Ú	is_mobile¤  s    r´   c                 C   s:   |   d|i¡}|r"| di ¡}|S td|› d�ƒ i S dS )aq  
   # Obtiene los id de los centros a los cuales tiene permiso el usuario
   # especificado, en la coleccion indicada y los entrega como un diccionario.
   #
   #Args:
   #users_collection: coleccion en la cual se encuentran los permisos de los usuarios (DB users) .
   #username: string con nombre de usuario.
   #
   #Returns:
   #Dict {region: [{area : [id_centro]}]} donde:
   #- region es un string que representa la region a la que pertenece el centro.
   #- area es un string que representa la comuna a la que pertenece el centro.
   #- id_centro es un string que representa el identificador unico de cada centro.
    rŒ   Úpermisosú	Usuario 'ú' no encontrado.N)r‘   r�   rm   )r“   rŒ   Úusuariorµ   rq   rq   rr   Úget_accesos_usuario¬  s    r¹   c                 C   s   | rdS dS d S ©NTFrq   ©rµ   rq   rq   rr   Úvalidacion_permisos_usuarioË  s    r¼   c                 C   sb   | t  j}| d|i¡}|rJ| di ¡}||kr<tdƒ dS tdƒ dS ntd|› d�ƒ d S d S )	NrŒ   Úaccess_tokenzLos tokens SI coincidenTzLos tokens NO coincidenFr¶   r·   )r�   rf   r‘   r�   rm   )r’   rŒ   r½   r“   r¸   Útokenrq   rq   rr   Úcheck_tokenÓ  s    
r¿   c                 C   s2   |   ddi¡}g }|D ]}| |d ¡ q|}|S )aN  
   # Obtiene los id de los centros en los cuales esta operativo el servicio
   # Scapp.
   #
   #Args:
   #ciclos_collection: coleccion en la cual se encuentran el estado de los
   # servicios por centro.
   #
   #Returns:
   #Array1D (scapp_activos) donde:
   #- scapp_activos son todos los id de centros que contrataron Scapp.
    zscapp.statusTÚ	centro_id©ÚfindÚappend)Úciclos_collectionÚqueryZscapp_activosÚresrq   rq   rr   Úservicios_activos_scappç  s    rÇ   c                 C   s@   |   ddi¡}g }|D ]}| |d ¡ qtd|›�ƒ |}|S )a]  
    # Obtiene los id de los centros en los cuales esta operativo el servicio
    # Enviro.
    #
    #Args:
    #ciclos_collection: coleccion en la cual se encuentran el estado de los
    # servicios por centro.
    #
    #Returns:
    #Array1D (enviro_activos) donde:
    #- enviro_activos son todos los id de centros que contrataron Enviro.
     zenviro.statusTrÀ   zenviro_activos=)rÂ   rÃ   rm   )rÄ   rÅ   Zenviro_activosrÆ   rq   rq   rr   Úservicios_activos_enviroþ  s    rÈ   c                 C   s2   |   ddi¡}g }|D ]}| |d ¡ q|}|S )a]  
    # Obtiene los id de los centros en los cuales esta operativo el servicio
    # Nanoox.
    #
    #Args:
    #ciclos_collection: coleccion en la cual se encuentran el estado de los
    # servicios por centro.
    #
    #Returns:
    #Array1D (nanoox_activos) donde:
    #- nanoox_activos son todos los id de centros que contrataron Nanoox.
     znanoox.statusTrÀ   rÁ   )rÄ   rÅ   Znanoox_activosrÆ   rq   rq   rr   Úservicios_activos_nanoox  s    rÉ   c                 C   s2   |   ddi¡}g }|D ]}| |d ¡ q|}|S )aQ  
    # Obtiene los id de los centros en los cuales esta operativo el servicio
    # PSS.
    #
    #Args:
    #ciclos_collection: coleccion en la cual se encuentran el estado de los
    # servicios por centro.
    #
    #Returns:
    #Array1D (pss_activos) donde:
    #- pss_activos son todos los id de centros que contrataron PSS.
     z
pss.statusTrÀ   rÁ   )rÄ   rÅ   Zpss_activosrÆ   rq   rq   rr   Úservicios_activos_pss+  s    rÊ   c                 C   sB   dddidddddgiigi}|   |dd	d
œ¡}dd„ |D ƒ}|S )z�
    Retorna una lista de IDs de centros que tienen el servicio FLUX activo.
    Soporta status booleanos (True) y strings ('A', 'B', 'C').
    ú$orzflux.statusTú$inÚAÚBÚCrŽ   r   )rÀ   Ú_idc                 S   s   g | ]}|d  ‘qS ©rÀ   rq   ©Ú.0Údocrq   rq   rr   Ú
<listcomp>P  s     z*servicios_activos_flux.<locals>.<listcomp>)rÂ   )rÄ   rÅ   ÚcursorZlista_centros_activosrq   rq   rr   Úservicios_activos_flux@  s    þÿr×   c                    sˆ   | }|}dd„ |  ¡ D ƒ}tt|ƒt|ƒ@ ƒ‰ ˆ s6i S i }| ¡ D ]@\}}| ¡ D ].\}}	‡ fdd„|	D ƒ}
|
rR|
| |i ¡|< qRqB|S )a/  
    # Realiza la operacion logica "And (&)" o la interseccion entre
    # los id de centros a los que tiene permiso el usuario y los
    # servicios activos de cada centro, retornando los centros del servicio
    # en el formato de entrada para el Front End. 
    #
    #
    #Args:
    #diccionario_id_centros: diccionario con los id de los centros a los que tiene acceso
    # el usuario.
    #servicios_activos: arreglo con los id de los centros que poseen el servicio
    # especificado activo
    #
    #Returns:
    #Dict {region: [{area : [nombre_centro]}]} donde:
    #- region es un string que representa la region a la que pertenece el centro.
    #- area es un string que representa la comuna a la que pertenece el centro.
    #- nombre_centro es un string que representa el nombre de cada centro.
     c                 S   s(   g | ] }|  ¡ D ]}|D ]}|‘qqqS rq   )Úvalues)rÓ   ZsubdiccionarioÚlistaÚvalorrq   rq   rr   rÕ   o  s     
    z7interseccion_permisos_con_servicios.<locals>.<listcomp>c                    s"   g | ]}|ˆ kr|  d ¡d ‘qS )ú-r   )Úsplit)rÓ   Zdestino©Zinterseccionrq   rr   rÕ   ~  s      )rØ   ÚlistÚsetÚitemsÚ
setdefault)Zdiccionario_id_centrosÚservicios_activosÚdiccionarioZarregloZvalores_tercer_nivelZdiccionario_actualizadoÚregionZsubregionesZ	subregionZdestinosZdestinos_actualizadosrq   rÝ   rr   Ú#interseccion_permisos_con_serviciosU  s    rå   c                 C   s   | rdS dS d S rº   rq   r»   rq   rq   rr   r¼   …  s    c              
   C   sö  |  d¡}|  d¡}|  d¡}|  d¡}|  d¡}|rF|rF|rF|rF|sVtddiƒdfS |  d|i¡r|tdd	|› d
�iƒdfS t|ƒdk r˜tddiƒdfS t|ƒs°tddiƒdfS t|ƒ}||d< �zÈ|  d|i¡}	|	d }
t|	d | jj|ƒ}|
dk�r
tddiƒdfW S |}|dk�rø|dk�r:t	|ƒ�r:t
|||ƒ}n¾|dk�r\t|ƒ�r\t
|||ƒ}nœt|ƒ�rôi }| ¡ D ]~\}}||k�rˆ�qr| |i ¡ | ¡ D ]P\}}||| k�r¶�qœi || |< || | D ]}| ¡ || | |< �qÎ�qœ�qrn|}t|| jj|ƒ}t|
||ƒ}|d k�r0tddiƒdfW S ||d< | t|ƒ¡ t|
|ƒ�rv|  |¡ tdd|› d�iƒdfW S tddiƒdfW S W nf tk
�rð } zFtd|› d|› d|jj› �ƒ tdd|› dt|ƒ› �iƒdf W Y ¢S d }~X Y nX d S )NrŒ   ÚpasswordÚcargoÚcorreorµ   Úmensajeú*Faltan campos necesarios para el registro.é�  úEl nombre de usuario ú ya existe.é™  é   u"   La contraseÃ±a es demasiado corta.u)   Formato de correo electrÃ³nico invÃ¡lido.ÚOperarioú&No tienes permiso para crear usuarios.)ú	Jefe AreaúJefe Regionrò   ró   u&   Permisos invÃ¡lidos para este usuario.é‘  u   CreaciÃ³n de usuario z  exitosa con permisos asignados.éÉ   ú)No se puede continuar por falta de rango.úError al crear usuario ú: ú éô  )r�   r   r‘   ÚlenÚ_check_email_formatr%   r
   ÚdatabaseÚciclosÚ!es_formato_simplificado_jefe_areaÚ"transformar_permisos_simplificadosÚ#es_formato_simplificado_jefe_regionÚes_formato_area_sin_centrosrà   rá   ÚcopyÚvalidacion_permisos_a_otorgarÚupdateÚ#construir_campos_auxiliares_usuarioÚverificar_permisosÚ
insert_oner¬   rm   Ú__traceback__Ú	tb_linenoÚstr)Úusuarios_collectionÚ	data_userÚusuario_actualrŒ   ræ   rç   rè   Úpermisos_solicitadosÚhashed_passwordÚusuario_actual_infoÚcargo_actualÚpermisos_actualÚpermisos_procesadosrä   ÚareasÚareaÚ	serviciosÚcentroÚpermisos_validadosr­   rq   rq   rr   Úcrear_usuarioŒ  s‚    






  ÿ  ÿ

"  ÿ

r  c                 C   sv   t | tƒsdS |  ¡ D ]Z\}}t |tƒs. dS | ¡ D ]8\}}t |tƒsP  dS tdd„ | ¡ D ƒƒr6  dS q6qdS )zì
    Detecta estructuras como region -> area -> servicios (sin centros).
    Ejemplo:
    {
      'loslagos': {
        'chiloe': {
          'enviro': {'status': False},
          'nanoox': {'status': True}
        }
      }
    }
    Fc                 s   s    | ]}t |tƒod |kV  qdS )r¢   N)Ú
isinstanceÚdict)rÓ   Úvrq   rq   rr   Ú	<genexpr>ð  s     z.es_formato_area_sin_centros.<locals>.<genexpr>T)r  r  rà   ÚallrØ   )rµ   rä   r  r  r  rq   rq   rr   r  Ú  s    


r  c              
   C   s<  |  d¡}|  d¡}|  d¡}|  d¡}|  d¡}||d< |rN|rN|rN|rN|s^tddiƒdfS |  d|i¡r„tdd	|› d
�iƒdfS t|ƒdk r tddiƒdfS t|ƒs¸tddiƒdfS t|ƒ}||d< �z|  d|i¡}	|	d }
|	d }|
dk�rtddiƒdfW S t|
|ƒ�r¼|dk�r\t|||ƒ}t|
||ƒ}|d k	�rH||d< ntddiƒdfW S n2t|
||ƒ}|d k	�r|||d< ntddiƒdfW S |  	|¡ tdd|› d|d › d�iƒdfW S tddiƒdfW S W nf t
k
�r6 } zFtd|› d|› d|jj› �ƒ tdd|› dt|ƒ› �iƒdf W Y ¢S d }~X Y nX d S )NrŒ   ræ   rç   rè   rµ   ré   rê   rë   rì   rí   rî   rï   z!La contrasena es demasiado corta.z'Formato de correo electronico invalido.rð   rñ   )ró   rò   z%Permisos invalidos para este usuario.rô   zCreacion de usuario z exitosa con permisos Ú.rõ   rö   r÷   rø   rù   rú   )r�   r   r‘   rû   rü   r%   r  r   r  r  r¬   rm   r	  r
  r  )r  r  r  rŒ   ræ   rç   rè   r  r  r  r  r  Zpermisos_transformadosr  r­   rq   rq   rr   Úoriginal_crear_usuarioõ  sN    











$r!  c                 C   sh   ddddddg}| |kr t dƒ‚||kr0t dƒ‚| | ¡}| |¡}||krXtd	ƒ d
S tdƒ dS d S )NÚSuperusuariorj   ró   rò   úJefe Centrorð   ú,El cargo del usuario existente no es valido.ú(El cargo del usuario nuevo no es valido.ú(El usuario tiene permiso para continuar.Tz-El usuario no tiene permiso para continuar 1.F©Ú
ValueErrorÚindexrm   )Úcargo_usuario_existenteZcargo_usuario_nuevoÚcargos_jerarquicosÚindice_usuario_existenteÚindice_usuario_nuevorq   rq   rr   r  .  s    

r  c              
   C   s:  i }zôt d| ¡ ›�ƒ | dkr„| ¡ D ]X\}}||kr(i ||< ||  ¡ D ]2\}}i || |< |D ]}| ¡ || | |< qdqLq(nr| dkrö| ¡ D ]`\}	}|	 d¡\}}||kr”||| kr”i | |i ¡|< || | D ]}| ¡ || | |< qÚq”W n< tk
�r4 }
 zt d|
› d|
jj› �ƒ W 5 d }
~
X Y nX |S )Nzpermisos_simplificados.items()=ró   rò   rÛ   z-Error al transformar_permisos_simplificados: rù   )rm   rà   r  rÜ   rá   r¬   r	  r
  )rç   Zpermisos_simplificadosZpermisos_usuario_actualÚnuevos_permisosrä   r  r  Úcentrosr  Úregion_arear­   rq   rq   rr   r   B  s*    *r   c                 C   sh   ddddddg}| |kr t dƒ‚||kr0t dƒ‚| | ¡}| |¡}||krXtd	ƒ d
S tdƒ dS d S )Nr"  rj   ró   rò   r#  rð   r$  r%  r&  Tz+El usuario no tiene permiso para continuar.Fr'  )r*  Zcargo_usuario_a_editarr+  r,  r-  rq   rq   rr   Úverificar_permisos_de_edicionZ  s    

r1  c                    s   ‡ ‡fdd„ˆD ƒ}|S )Nc                    s0   i | ](‰ ˆ ˆkrˆ ‡‡‡ fd d„ˆˆ  D ƒ“qS )c                    s:   i | ]2‰ ˆ ˆˆ krˆ ‡ ‡‡‡fd d„ˆˆ ˆ  D ƒ“qS )c                    sD   i | ]<‰ ˆ ˆˆ ˆ krˆ ‡‡ ‡‡‡fd d„ˆˆ ˆ ˆ  D ƒ“qS )c              	      s8   i | ]0}|ˆˆ ˆ  ˆ   |ˆˆ ˆ  ˆ   |¡¡“qS rq   ©r�   )rÓ   Úsubkey)r  Úkeyr  Úpermisos_x_crearrä   rq   rr   Ú
<dictcomp>t  s   ÿ zLpermisos_comunes_region.<locals>.<dictcomp>.<dictcomp>.<dictcomp>.<dictcomp>rq   ©rÓ   )r  r  r5  rä   )r4  rr   r6  s  s   û þzApermisos_comunes_region.<locals>.<dictcomp>.<dictcomp>.<dictcomp>rq   r7  ©r  r5  rä   ©r  rr   r6  r  s   	÷ 
ûz6permisos_comunes_region.<locals>.<dictcomp>.<dictcomp>rq   r7  ©r  r5  ©rä   rr   r6  q  s   ó 	÷z+permisos_comunes_region.<locals>.<dictcomp>rq   )r  r5  Zpermisos_comunesrq   r:  rr   Úpermisos_comunes_regionp  s    ór<  c                 C   sL   t | tƒs| S i }|  ¡ D ],\}}t |tƒr:d|i||< qt|ƒ||< q|S )Nr¢   )r  r  rà   ÚboolÚconvertir_diccionario)rã   Ú	resultadoÚclaverÚ   rq   rq   rr   r>  ƒ  s    

r>  c                    s   ‡ ‡fdd„ˆD ƒ}|S )Nc                    s8   i | ]0‰ ˆ ˆkrˆ ˆkrˆ ‡‡‡ fd d„ˆˆ  D ƒ“qS )c                    sD   i | ]<‰ ˆ ˆˆ krˆ ˆˆ krˆ ‡ ‡‡fd d„ˆˆ ˆ  D ƒ“qS )c                    s    g | ]}|ˆˆ ˆ  kr|‘qS rq   rq   ©rÓ   r  )r  r5  rä   rq   rr   rÕ   ’  s      z9centros_comunes.<locals>.<dictcomp>.<dictcomp>.<listcomp>rq   r7  r8  r9  rr   r6  ‘  s
    þ z.centros_comunes.<locals>.<dictcomp>.<dictcomp>rq   r7  r:  r;  rr   r6  �  s    ú þz#centros_comunes.<locals>.<dictcomp>rq   )r  r5  Zvalores_comunesrq   r:  rr   Úcentros_comunes�  s    ú	rB  c                 C   s   t t||ƒƒS rv   )Úverificar_nivel_vacior<  )Zcargo_usuario_actualr  r5  rq   rq   rr   r  œ  s    r  c                    s   ‡ fdd„‰ ˆ | dƒS )Nc                    s~   |dkr| S |   ¡ D ]d\}}t|tƒrn|dk rZˆ ||d ƒ}|d krJ d S |i krl d S qx|dkrx|sx d S q|s d S q| S )Nrï   rŽ   )rà   r  r  )rã   Znivelr@  rÚ   r?  ©Ú	verificarrq   rr   rE  £  s    
z(verificar_nivel_vacio.<locals>.verificarrŽ   rq   )rã   rq   rD  rr   rC  ¢  s    rC  c                 C   s   t  d| ¡S )Nz[^@]+@[^@]+\.[^@]+)r°   Úmatch)Zemailrq   rq   rr   rü   ¹  s    rü   c                 C   sH   d|i}|   |¡}|jdkr0td|› d�ƒ dS td|› d�ƒ dS dS )	a'  Funcion para eliminar un usuario de la base de datos.
    
    Parametros:
    - users_collection: La coleccion de MongoDB donde se almacenan los usuarios.
    - username (str): El nombre de usuario para identificar el documento a eliminar.
    
    Retorna:
    - Un codigo de estado HTTP.
    rŒ   r   r¶   ú' eliminado correctamente.éÈ   ú/' no encontrado o no se elimino ningun usuario.rë   N)Ú
delete_oneÚdeleted_countrm   )r“   rŒ   Úfiltror?  rq   rq   rr   Úeliminar_usuario½  s    

rM  c                 C   sZ  |d krt dƒ‚t|d | jj|ƒ}|d }|  d|i¡}|sFt dƒ‚| d|d ¡}td|›�ƒ | d¡}td|›�ƒ |d k	�r(|dkr¤t|ƒr¤t|||ƒ}n2|d	krÖt	|ƒrÖt
d
d„ | ¡ D ƒƒrÖt|||ƒ}td|›�ƒ t|| jj|ƒ}	t|||	ƒ}
|
d k�rt dƒ‚|
|d< | t|
ƒ¡ d|k�rBt|d ƒ|d< |  d|id|i¡ d S )Nz&No se ha proporcionado info del editorrµ   rç   rŒ   úUsuario no encontrado.zcargo_nuevo=zin permisos_nuevos=rò   ró   c                 s   s   | ]}d |kV  qdS )rÛ   Nrq   ©rÓ   Úkrq   rq   rr   r    s     z"editar_usuarios.<locals>.<genexpr>zout permisos_nuevos=z1Permisos invalidos o superiores a los del editor.ræ   ú$set)r¬   r
   rý   rþ   r‘   r�   rm   rÿ   r   r  r  Úkeysr  r  r  r%   Ú
update_one)Ú	users_colrŒ   ÚupdatesÚeditor_infoZpermisos_editorÚcargo_editorZuser_targetZcargo_nuevoÚpermisos_nuevosZnuevos_permisos_finalr  rq   rq   rr   Úeditar_usuariosë  sP    

  ÿÿ  ÿ  ÿ

rY  c                 C   s8   t | tƒsdS |  ¡ D ]}t |tƒr,d|kr dS qdS )NFr¢   T)r  r  rØ   )Údr  rq   rq   rr   Úes_servicio_dict  s    
r[  c                 C   s$   |   ¡ D ]\}}t|ƒs dS qdS )NFT©rà   r[  )rX  rä   r  rq   rq   rr   r     s    r  c                 C   s,   |   ¡ D ]\}}d|ks t|ƒs dS qdS )NrÛ   FTr\  )rX  rP  r  rq   rq   rr   rÿ   '  s    rÿ   c                 C   s^   t |tƒs|S t | tƒr |  ¡ ni }| ¡ D ],\}}||krPt|| |ƒ||< q,|||< q,|S )z‘
    Merge profundo: actualiza solo los valores presentes en nuevos_permisos.
    Mantiene los demas valores del arbol de permisos original.
    )r  r  r  rà   Úmerge_permisos)Zpermisos_actualesr.  r?  r@  Znuevo_valorrq   rq   rr   r]  .  s    

r]  c                 C   s@   i }|   ¡ D ].\}}|d k	rt|tƒr2| ¡ dkr|||< q|S )NÚ )rà   r  r  Ústrip)Z	json_dataZcampos_filtradosr4  Úvaluerq   rq   rr   Úfiltrar_campos?  s
    
ra  c              
   C   s®   i }| d D ]œ}|d d   ¡ }|d }||kr8i ||< |D ]j}|d   ¡ }|d }||| krli || |< | ¡ D ]0\}}	|	}
|
|| | |  ¡ › d|› d|› �< qtq<q|S )Nrµ   ÚREGIONr   ZAREASÚAREAÚCENTROrÛ   )Úlowerrà   )Údatar?  Úpermisorä   r  Zarea_objr  r/  r  ZsistemasZcentro_formatorq   rq   rr   Útransformar_permisosG  s    *rh  c                 C   s:   d|› d|› �}t | tƒr6|  |¡r6| d t|ƒ … S | S ©NrÛ   )r  r  r£   rû   )rÀ   r  rä   Zsufijorq   rq   rr   Úextraer_nombre_centro_desde_idb  s    rj  c                 C   sH  g }g }g }t ƒ }i }t| tƒs0|||g |dœS |  ¡ D ]â\}}| |¡ t|tƒsVq8| ¡ D ]º\}}	| |› d|› �¡ t|	tƒs†q^|	 ¡ D ]ˆ\}
}t|
||ƒ}|› d|› d|› �}| |¡ g }t|tƒ�r| ¡ D ]4\}}t|tƒrØ| d¡dkrØ| |¡ | |¡ qØ|||< qŽq^q8tt |ƒƒtt |ƒƒtt |ƒƒt|ƒ|dœS )N)Úregionesr  r/  r  ZserviciosPorCentroú:r¢   T)	rß   r  r  rà   rÃ   rj  r�   ÚaddÚsorted)rµ   rk  r  r/  r  Zservicios_por_centrorä   Z
areas_dictr  Zcentros_dictrÀ   Zservicios_dictZnombre_centroZcentro_frontrâ   ÚservicioÚconfigrq   rq   rr   r  h  sJ    
û







ûr  c                 C   sH   ddddddg}|  | ¡}|  |¡}||kr8tdƒ dS td	ƒ d
S d S )Nr"  rj   ró   rò   r#  rð   r&  Tz-El usuario no tiene permiso para continuar 2.F)r)  rm   )r*  Zcargo_usuario_dbr+  r,  Zindice_usuario_dbrq   rq   rr   Úverificar_permisos_edicionš  s    

rq  c                 C   s:   t jd }t jd t jd< t| |ddid�}|t jd< |S )Nr   r€   ÚresetT)ÚidentityÚexpires_deltaZadditional_claims)Úapprp  r   )rŒ   rt  Úoriginal_keyr¾   rq   rq   rr   Úcreate_reset_tokenÎ  s
    

rw  c                 C   s0   t jd }t jd t jd< t| ƒ}|t jd< |S )Nr   r€   )ru  rp  r#   )r¾   rv  Údecodedrq   rq   rr   Údecode_reset_token×  s
    

ry  c                 C   s¶  g }| t  }| t }|j}|j}|j}g }	td|› �ƒ |D �]¦}
td|
›�ƒ | d|
d i¡}zìt ¡ }|
 	di ¡ |
d  	di ¡ |
d  	di ¡ |
d  
d¡p¨d ¡  ¡ }|dkrìd |
d d d	< d |
d d d
< d |
d d d< n8||
d d d< |
d d  	d	d ¡ |
d d  	d
d ¡ |
d d  	d	d ¡ |
d d  	d
d ¡ W nT tk
�r¢ } z4td|jj› d|› �ƒ tddiƒdf W Y ¢  S d }~X Y nX |d k�rÌ| t|
ƒ¡ |	 |
d ¡ q<|r<td|d › d�ƒ q<zz|j|ddd�}td|j› d�ƒ t|	ƒdk�rPtdt|	ƒ› d�ƒ |	D ]}t||ƒ t|||dƒ �q0tddiƒdfW S  tk
�r° } z0td|› d|jj› �ƒ tddiƒdf W Y ¢S d }~X Y nX d S ) Nzcentros_recibidos: zinfo_centro=rÀ   Úgps_coordinatesÚmanualÚautoZactiver^  ÚlatÚlonÚ	timestampz?No se ha convertido timestamp log de centro por error en linea ú: 
ré   ú!No se logro realizar la operacionrú   ú
El centro z ya esta registrado 
FT)ÚorderedZbypass_document_validationzInsertados: z documentosr   z
Se cumple z>0Z
add_centerz Exito en crear centros! rH  z	Warning: u    Ì£Ì£Ì£ )r�   ÚENVIRO_DATABASE_NAMErþ   Úhistorial_usersÚestadosrm   r‘   r   Únowrá   r�   r_  re  r¬   r	  r
  r   rÃ   r(   Ú
bulk_writeZinserted_countrû   Úcrear_estado_centro_defaultr1   )r’   rŒ   r/  ÚoperacionesÚuser_dbÚ	enviro_dbrÄ   Úusers_historial_collectionÚestado_centros_collectionZcentros_insertadosZinfo_centroZcomprobacionZdtZactive_moder­   r?  Zcentro_creadorq   rq   rr   Úciclos_insertß  s\    
	*

r�  c                 C   s$   g }|   ¡ D ]}| |d ¡ q|S )NrÀ   rÁ   )Zcoleccion_ciclosr/  Zdatorq   rq   rr   Úcentros_en_db*  s    r�  c              
   C   sú   |› d|› d|› �}|ddiddiddiddiddidœi}t ddd|› d|› d|› �d	d
iidd|› d|› d|› �|| iid
d�t ddd|› d|› d|› �d	d
iidd|› d|› d|› �|| iid
d�g}|  |¡}|jdksî|jdkròdS d
S dS )zÒ
    Actualiza los permisos de un usuario en MongoDB sin sobrescribir datos existentes.
    
    Parameters:
    - region: Nombre de la region.
    - area: Nombre del area.
    - centro: Nombre del centro.
    rÛ   r¢   T©ra   rb   rc   rd   re   rŒ   Zitgú	permisos.r   ú$existsFrQ  ©ZupsertZitg7r   N)r'   rˆ  Úmodified_countÚupserted_count)r“   rä   r  r  Zpermiso_keyrg  rU  Úresultrq   rq   rr   Úguardar_permiso0  sD    
 ÿ ÿ ÿ ÿ ÿóÿ  ý  ýù
r˜  c                 C   s@   | j }| j}t|ƒD ]"}| d¡\}}}t||||ƒ qtdƒS )NrÛ   z/Todos los permisos de superusuario actualizados)rþ   rf   r�  rÜ   r˜  rm   )r‹  rÄ   r“   r  r  rä   rq   rq   rr   Úpermisos_superusuariog  s    r™  c           $      C   s  |j }|j}| rt| tƒs&tdƒ dS d}| D �]Ø}�zv| d¡}|rPt|tƒsTW q.| ¡  ¡ }| 	d¡}t
|ƒdk rˆtd|› �ƒ W q.|d }	|d	 }
td
d„ ||	|
fD ƒƒrÂtd|› �ƒ W q.i }dD ]B}| |¡}t|tƒrþ| d¡| d¡dœ||< qÊdddœ||< qÊd|	› d|
› d|› �}dddd|	› d|
› �ddiiddd|	› �ddiigi}ddddd|	› �di}| ||¡}g }g }|D �]®}| d¡}| dd¡}| d¡�p²i }| |	¡}t|tƒ�sÎ�qˆ| |
¡}t|tƒ�rò||k�rò�qˆd}|dk�rBt|tƒ�rìt
|ƒdk�rìtt|ƒƒ}t| |¡tƒ�rì|| }nª|dk�rìt|tƒ�rŽt
|ƒdk�rŽtt|ƒƒ}t| |¡tƒ�rì|| }n^| ¡ D ]T\}}t|tƒ�r–t
|ƒdk�r¼�q–tt|ƒƒ}t| |¡tƒ�r–|| } �qì�q–|dk�rú|}d|d |ddii}| t|d||iiƒ¡ | ||d œ¡ �qˆ|�rˆ|j|dd!�}|j} | dk�rŒ|D ]"}!t|d"|!d# |!d$ gd%d&� �qbnd} || 7 }td'|› d(| › d)�ƒ W q. tk
�r }" z:tt|"d*dƒd+d,ƒ}#td-| dd.¡› d/|#› d0|"› �ƒ W 5 d}"~"X Y q.X q.td1|› d2�ƒ dS )3u·  
    Procesa data_centros (lista) y agrega automÃ¡ticamente permisos a jefaturas.
    - Jefe Area: requiere permisos.<region>.<area>
      Copia template desde el primer centro en esa area.
    - Jefe Region: requiere permisos.<region>
      Copia template primero desde esa area; si no hay, desde cualquier otra area de la region.
    Si no hay template disponible, usa fallback desde el input (enviro/nanoox/scapp/pss con init/fin).
    õ9   Advertencia: data_centros estÃ¡ vacÃ­o o no es una lista.Nr   rÀ   rÛ   rï   zError formato ID insuficiente: éÿÿÿÿéþÿÿÿc                 s   s   | ]}d |kpd|kV  qdS ©r   ú$Nrq   ©rÓ   Úxrq   rq   rr   r  ”  s     z5original_actualizar_permisos_jefes.<locals>.<genexpr>uJ   Error: centro_id/area/region contienen caracteres invÃ¡lidos ('.' o '$'): )ra   rb   rc   rd   ÚinitÚfin)r¡  r¢  r’  r   rË   rç   rò   r“  Tró   rŒ   rŽ   ÚDesconocidorµ   rÐ   FrQ  ©Útarget_userr  ©rƒ  z$Systemr¥  r  Zadd_center_permission)Ú
collectionrŒ   Zedit_objectZlog_typezCentro 'z': Se actualizaron z usuarios (Bulk).r	  r
  ú?zError procesando centro Zdescu   : en lÃ­nea ú:
z4=== Proceso Finalizado. Total usuarios modificados: z ===)rf   r…  r  rÞ   rm   r�   r  r_  re  rÜ   rû   Úanyr  rÂ   ÚnextÚiterrà   rÃ   r'   rˆ  r•  r1   r¬   Úgetattr)$Údata_centrosr‹  Úuser_collectionr�  Úcount_total_updatesÚitemÚcentro_id_rawrÀ   Úpartesrä   r  Úfallback_serviciosrP  r  Ú
mongo_pathrÅ   Ú
projectionÚusers_cursorÚbulk_operationsÚ
logs_queuer•   rç   rŒ   rµ   Úpermisos_regionÚpermisos_area_actualÚtemplateÚprimer_centroÚ_Ú	area_dictÚfiltro_updater—  Úupdates_localÚentryr­   Úlinenorq   rq   rr   Ú"original_actualizar_permisos_jefeso  sÈ    





þÿ









  þ
þÿþ
ü6rÄ  c           $         sÆ  |j }|j}| rt| tƒs&tdƒ dS d}dddddg}| D �]‚}�z®| d	¡}|r^t|tƒsbW q<| ¡  ¡ }| 	d
¡}	t
|	ƒdk rˆW q<|	d }
|	d }tdd„ ||
|fD ƒƒr´W q<i }|D ]F}| |¡}t|tƒrò| d¡| d¡ddœ||< q¼ddddœ||< q¼d|
› d|› d|› �}dddd|
› d|› �ddiiddd|
› �ddiigi}ddddd|
› �di}| ||¡}g }g ‰|D �]}| d¡}| dd¡}| d¡�p¨i }t|tƒ�sÐt d ||t|ƒj¡ �q~| |
¡}t|tƒ�st d!|||
t|ƒj¡ �q~| |¡}t|tƒ�r&||k�r&�q~d}|dk�rzt|tƒ�r,t
|ƒdk�r,tt|ƒƒ}t| |¡tƒ�r,||  ¡ }n²|dk�r,t|tƒ�rÊt
|ƒdk�rÊtt|ƒƒ}t| |¡tƒ�r,||  ¡ }nb| ¡ D ]X\}}t|tƒ�rÒt
|ƒdk�rø�qÒtt|ƒƒ}t| |¡tƒ�rÒ||  ¡ } �q,�qÒ|dk	�rZ|D ]}||k�r:|| ||< �q:n|}d"|d" |ddii}| t|d#||iiƒ¡ ˆ ||d$œ¡ �q~d} |�rÜ|j|dd%�}!|!j} t d&|d' d(d„ ˆD ƒ¡¡ nt d)|¡ || 7 }W q< tk
�r„ }" zr‡fd*d+„|"j d,g ¡D ƒ‰ ‡ fd-d+„ˆD ƒ}#|#�rTt d&| d	¡d' |#¡¡ t d.| d	¡d' ˆ ¡�ppd/¡ W 5 d}"~"X Y q< tk
�r¾ }" ztjd0| d	¡|"dd1� W 5 d}"~"X Y q<X q<dS )2u/   
    VERSIÃ“N CORREGIDA PARA SOPORTAR FLUX
    rš  Nr   ra   rb   rc   rd   re   rÀ   rÛ   rï   r›  rœ  c                 s   s   | ]}d |kpd|kV  qdS r�  rq   rŸ  rq   rq   rr   r  ,  s     z,actualizar_permisos_jefes.<locals>.<genexpr>r¡  r¢  F)r¡  r¢  r¢   r’  r   rË   rç   rò   r“  Tró   rŒ   rŽ   r£  rµ   zQpermisos.jefe_omitido usuario=%s centro=%s motivo='permisos' no es un objeto (%s)zTpermisos.jefe_omitido usuario=%s centro=%s motivo='permisos.%s' no es un objeto (%s)rÐ   rQ  r¤  r¦  z.permisos.jefes_concedido centro=%s usuarios=%sú,c                 s   s   | ]}|d  V  qdS )r¥  Nrq   ©rÓ   Úqrq   rq   rr   r  ›  s     zHpermisos.jefes_sin_cambios centro=%s (sin jefes pendientes de recibirlo)c                    s<   g | ]4}t | d ¡tƒr|d  tˆ ƒk rˆ |d   d ‘qS )r)  r¥  )r  r�   Úintrû   )rÓ   Úerr)r¹  rq   rr   rÕ   ¤  s     ÿz-actualizar_permisos_jefes.<locals>.<listcomp>ÚwriteErrorsc                    s    g | ]}|d  ˆ kr|d  ‘qS )r¥  rq   rÆ  )Úfallidosrq   rr   rÕ   ¦  s      uc   permisos.jefes_fallido centro=%s usuarios=%s motivo=nodo de permisos invÃ¡lido o error de escrituraZno_identificadosz8permisos.jefes_propagacion_incompleta centro=%s error=%s)Úexc_info)rf   r…  r  rÞ   rm   r�   r  r_  re  rÜ   rû   rª  r  rÂ   r   rt   r‰   rx   r«  r¬  r  rà   rÃ   r'   rˆ  r•  rs   Újoinr+   Údetailsr¬   )$r®  r‹  r¯  r�  r°  ÚSERVICIOS_SOPORTADOSr±  r²  rÀ   r³  rä   r  r´  rP  r  rµ  rÅ   r¶  r·  r¸  r•   rç   rŒ   rµ   rº  r»  r¼  r½  r¾  r¿  Zservicio_nuevorÀ  rÁ  r—  r­   Z
concedidosrq   )rË  r¹  rr   Úactualizar_permisos_jefes  s   




þÿ

  þ
   þ





  þ
þÿþ ÿ ÿ þ  þrÐ  c                 C   sP   i }|   ¡ D ]>\}}|  ¡ D ],\}}|dkr||kr<i ||< ||| |< qq|S )N)r^  N©rà   )ÚdatosÚvalores_actualizadosr4  Úsubdictr3  r`  rq   rq   rr   Úfiltrar_valores²  s    rÕ  c                 C   s¼   t |ƒ}td|›�ƒ | d¡}|r,|d }td|›�ƒ |d k	r^d|kr^d|kr^t ¡ |d< |sztdƒ td	d
iƒdfS dd„ | ¡ D ƒ}|  |d|i¡}|jdkr°tdƒ ntdƒ d S )Nzvalores_actualizados=rz  r{  zgps=r}  r~  r  zNo hay valores para actualizar.ré   zEl centro no existerú   c                 S   s2   i | ]*\}}|  ¡ D ]\}}|› d |› �|“qqS )r   rÑ  )rÓ   r4  rÔ  r3  r`  rq   rq   rr   r6  Î  s
   
 þ z(actualizar_documento.<locals>.<dictcomp>rQ  r   z#Documento actualizado exitosamente.z7No se encontro el documento o no se realizaron cambios.)	rÕ  rm   r�   r   r‡  r   rà   rS  r•  )rÄ   rL  rÒ  rÓ  ZgpsZupdate_queryr—  rq   rq   rr   Úactualizar_documento¼  s*    
ÿþ

rÖ  c                 C   s<   g }| D ].}| | D ] }| | | D ]}|  |¡ q$qq|S rv   )rÃ   )Zcentros_usuarioZlista_centrosrä   r  r  rq   rq   rr   Úobtener_lista_centrosÞ  s    r×  c                 C   s  |  d¡}|  i dddœ¡}dd„ |D ƒ}|D ]æ}|  d|i¡d }zª|rì|  d|i¡d |d	  |d  | }t|› d
|›�ƒ |  d|idd|d	 › d|d › d|› �dii¡}|jdkrÖtd|› d|› d�ƒ ntd|› d|› d�ƒ W q.   td|› d|› �ƒ Y q.Y q.X q.d S )NrÛ   r   rŽ   )rÐ   rŒ   c                 S   s   g | ]}d |kr|d  ‘qS ©rŒ   rq   rÒ   rq   rq   rr   rÕ   é  s      z/eliminar_centro_de_permisos.<locals>.<listcomp>rŒ   rµ   é   z, permiso_centro=ú$unsetr’  r   r^  zSe ha eliminado el centro z para el usuario zNo se encontro el centro z o ya fue eliminado.úEl usuario z" no posee permisos para el centro )rÜ   rÂ   r‘   rm   rS  r•  )r“   rÀ   Zcentro_splitrÅ   Úusuariosr¸   Zpermiso_centroZupdate_resultrq   rq   rr   Úeliminar_centro_de_permisosæ  s(    
&$þ
rÝ  c              
   C   s‚   z<|   d|i¡}|r:|  d|i¡}|jdkr:td|› �ƒ W n@ tk
r| } z"td|› d|jj› d|› �ƒ W 5 d }~X Y nX d S )NrÀ   r   z(Se han eliminado los estados del centro z0No se han podido eliminar los estado del centro ú por error en linea r€  )r‘   rJ  rK  rm   r¬   r	  r
  )rŽ  rÀ   rÅ   Údeleter­   rq   rq   rr   Úeliminar_estados_centroþ  s    
0rà  c                 C   s¼   | j }g }tt ¡  d¡||ddd d d d d dœ
ƒ}| |¡ z4|r^| |¡ td|› d�ƒ ntd|› d�ƒ W nF tk
r¶ } z(td	|› d
|› d|j	j
› d|› �ƒ W 5 d }~X Y nX d S )Nú%Y-%m-%dFÚsimple)
ÚfecharÀ   Úvariabler¢   ÚtipoÚaÚbÚcrZ  Zenviadoz
Umbral de ú creadozNo hay datos de umbral de z para guardarz#Error creando datos de umbrales de z para ú
 en linea r€  )Úumbralesr(   r   r‡  ÚstrftimerÃ   rˆ  rm   r¬   r	  r
  )rŒ  rÀ   ÚvarZcol_enviro_umbralesr¸  Ú	operationr­   rq   rq   rr   Úcrear_umbral_default	  s.    öÿ

rï  c                 C   s4   ddddg}|D ]}t | ||ƒ qtd|› �ƒ d S )NZOxigenoZDoxigenoZ	SalinidadZTemperaturaz2Se han creado los umbrales por defecto del centro )rï  rm   )rŒ  rÀ   Ú	variablesrí  rq   rq   rr   Úumbrales_default#  s    rñ  c              
   C   s    t dƒ zRg }t|ddddœƒ}| |¡ |rJ|  |¡ t d|› d�ƒ nt d|› �ƒ W n@ tk
rš } z"t d|› d|jj› d	|› �ƒ W 5 d }~X Y nX d S )
NzCREANDO ESTADO CENTRO DEFAULTrÎ   )rÀ   ra   rb   re   z,Estado de Servicios por defecto para centro ré  z8No hay datos para crear Estado de Servicios para centro z3Error creando Estado de Servicios por defecto para rê  r€  )rm   r(   rÃ   rˆ  r¬   r	  r
  )rŽ  rÀ   r¸  rî  r­   rq   rq   rr   r‰  )  s$    üÿ

0r‰  c                 C   sŽ   | r†g }| D ]F}t t| | d ƒƒD ],}| | d | d D ]}| |d ¡ q<q$q|jdd„ dd� tt ¡  d¡d	 |d
  ƒ}nd}|S )NÚcansÚbombasÚhorac                 S   s   t  | d¡S )Nz%H:%M:%S)r   Ústrptime)Úlast_msg_daterq   rq   rr   Ú<lambda>H  ó    z.get_last_measure_sensor_date.<locals>.<lambda>T)r4  Úreverserá  rù   r   r^  )Úrangerû   rÃ   Úsortr  r   r‡  rì  )Úmodulosrö  ÚidÚjÚbombaZ
final_daterq   rq   rr   Úget_last_measure_sensor_date?  s     r   c                 C   s>  t dƒ |rt|tƒsdS |D �]}zØ| dd¡ ¡ }| d¡}t|ƒdk rPW qz&|d }|d }d |dd… ¡}W n   Y W qY nX | d	¡}t|tƒs¢W q| 	¡ D ]N\}	}
|	 
¡  ¡ }|tkrªt|
tƒrªt| }| | t }t|||||
td
� qªW q tk
�r6 } zt d|› �ƒ W Y ¢qW 5 d}~X Y qX qdS )u‘   
    Guarda la configuraciÃ³n de emails. 
    Usa OP_SET para reemplazar la lista completa (Snapshot) en DB 
    con lo que viene del Front.
    z4Iniciando procesamiento de emails (Snapshot Mode)...NrÀ   r^  rÛ   rï   r›  rœ  rh   )rî  zError procesando emails item: )rm   r  rÞ   r�   r_  rÜ   rû   rÍ  r  rà   re  r0   ÚEMAIL_COLLECTION_NAMEr8   r:   r¬   )r’   r®  r±  rÀ   r³  Úc_regionÚc_areaZc_nomZemails_configZservicio_keyZlista_emailsZservicio_normalizadoÚdb_namer§  r­   rq   rq   rr   Úprocesar_configuracion_emailsQ  sD    

 

ú	r  r›   r^  )Údefaultsz/<path:path>c                 C   sT   t j dd¡}d}t|ƒrd}| dkrFtj tj || ¡¡rFt|| ƒS t|dƒS d S )Nrš   r^  r{   z
index.html)	r   r†   r�   r´   rª   r›   ÚexistsrÍ  r   )r›   r³   r|   rq   rq   rr   Úserve“  s    
r  z/check_server_statusZHEAD)r~   c                   C   s   dS )N)r^  rH  rq   rq   rq   rq   rr   Úcheck_server_status§  s    r	  z/pingc                   C   s   t dƒ tddiƒS )NZpongÚmessage)rm   r   rq   rq   rq   rr   Úping¬  s    r  z/loginc                  C   sœ  t ƒ } | t j}tj dd¡}td|› �ƒ tjsBtddiƒdfS tj	 dd¡}tj	 d	d¡}tj	 d
d¡}tdtj	› �ƒ |r„|s”tddiƒdfS | 
d|i¡}t|ƒ |r¾t| d	¡|ƒsÎtddiƒdfS t|d�}|rætdd�ntdd�}t||d�}	t|	ƒ}
|
d }| d|id||	|dœi¡ td|› d�ƒ || d¡dœ}|dk�rb||d< |	|d< t|ƒ}t||ƒ t||	| ¡ d� td |›�ƒ |d!fS )"zí 
    # login: inicio de sesion hibrido WEB/MOBILE, recibe unicamente la informacion a la que tiene acceso
    # recibe  json en el formato:
    #   {
    #       "username": "usuario",
    #       password": "password"
    #   }   
    úX-Client-TypeÚwebz[LOGIN] Cliente detectado: ré   zFalta JSON en la solicitudrë   rŒ   Nræ   ÚrememberFzjson: zFalta username o passwordzCredenciales invalidasrô   ©rs  r‚   rƒ   rÙ  )rs  rt  rˆ   rQ  )r½   Úrefresh_tokenr�   zusuario z logeado correctamenterç   )rŒ   rç   Úmobiler½   r  )Zmax_agezlogin resp =rH  )r/   r�   rf   r   r†   r�   rm   Zis_jsonr   Újsonr‘   r$   r   r   r   r#   Úupdate_manyr!   r"   Útotal_seconds)r’   r“   Úclient_typerŒ   ræ   r  r•   r½   Z
rt_expiresr  Z
decoded_rtZjti_refreshZresponse_dataÚresprq   rq   rr   Úlogin³  sD    


þ

r  z
/protectedc                  C   s   t ƒ } t| d�dfS )a¬  
    Ruta protegida que requiere un token de acceso (access token) valido en el encabezado Authorization.

    Esta funcion es util para verificar que un usuario ha iniciado sesion y tiene autorizacion para acceder a recursos protegidos.
    El token debe incluirse en el header HTTP como: Authorization: Bearer <access_token>

    Retorna:
        JSON con el nombre de usuario (identity) que esta actualmente autenticado.
    )Zlogged_in_asrH  )r   r   )Úcurrent_userrq   rq   rr   Ú	protected  s    r  z/refresh)r‹   c                  C   sb   t ƒ } t| d�}tj dd¡}td|› �ƒ |dkrDtd|dœƒ}ntddiƒ}t||ƒ |d	fS )
uÑ  
    Ruta para renovar el token de acceso (access token) hÃ­brido (web/mobile) utilizando un token de actualizacion (refresh token).

    Esta funcion permite al usuario mantener la sesion activa sin volver a iniciar sesion, 
    siempre que el refresh token aun sea valido.
    
    El refresh token debe incluirse en el encabezado HTTP como: Authorization: Bearer <refresh_token>

    Retorna:
        Un nuevo token de acceso (access_token) en formato JSON.
    r  r  r  z[REFRESH] Cliente detectado: r  zToken renovado)rp   r½   rp   rH  )r   r   r   r†   r�   rm   r   r!   )r  Znew_access_tokenr  r  rq   rq   rr   r‹     s    
þ

r‹   z/logoutc                  C   sn   t ƒ } tƒ }|t j}| d| idddii¡ tdd�}| tjd ¡ | tjd ¡ t	d	|›�ƒ |d
fS )NrŒ   rÚ  r�   r^  zLogout exitoso)rp   ZJWT_ACCESS_COOKIE_NAMEZJWT_REFRESH_COOKIE_NAMEzCerrando sesion resp=rH  )
r   r/   r�   rf   rS  r   Zdelete_cookieru  rp  rm   )rŒ   r’   r“   r  rq   rq   rr   Úlogout5  s    

þ
r  z7/<SERVICE>/receive_client_data/<REGION>/<AREA>/<CENTRO>c           
   
   C   s  | dk�r˜�z,t ƒ }|t j}| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }|}tj}|sŽtdƒ tddiƒdfW S |s¬tdƒ tddiƒdfW S |› d|› d|› �}t	|t
ƒrÞtdƒ | d	¡}nt	|tƒròtd
ƒ ntdƒ t|||ƒ t|||ƒ td|› �ƒ tdƒ tddiƒdfW S  tk
�r” }	 z<td|	jj› d|	› d�ƒ tddt|	ƒ› �iƒdf W Y ¢S d}	~	X Y nX nf| dk�rºtdƒ tddiƒdfS | dk�rÜtdƒ tddiƒdfS | dk�rþtdƒ tddiƒdfS dS )aÃ  # all_sensors_data['data']: [
            {
                'Nombre' 
                "fecha"
                "hora"
                "dif_last"
                "device_id"
                "dev_eui"
                "f_port"
                "snr"
                "rssi"
                "channel_rssi"
                "spreading_factor"
                "f_cnt"
                "uplink_message"
                "timeStamp"
                "batteryPercent"
                "Port 2"
                "formatted_time"
                "Port 3"
                "batteryVoltageMv"
                "flags"
                prof_i sensores data for i={0,1,2,3}
            } , 
            {...} , ...
        ]
         rg   rù   r^  rÛ   úDatos no recibidosré   rë   zEntramos al loop de <dict>rf  zEntramos al loop de <list>z/no se esta cumpliendo con la condicion de claseúGuardado datos desde centro úDatos recibidos exitosamenterH  z#Error en receive_client_data linea r€  úError al procesar los datos: rú   Nrb   z$Datos Nanoox se envian de otra formarc   z#Datos Scapp se envian de otra formard   z!Datos PSS se envian de otra forma)r/   r„  rf  ÚreplaceÚ
capitalizer   r  rm   r   r  r  r�   rÞ   Ú_save_client_dataÚcheck_metadatar¬   r	  r
  r  )
ÚSERVICErb  rc  rd  r’   Úenviro_data_collectionr§  Úall_sensors_dataÚcentroIdr­   rq   rq   rr   Úreceive_client_dataI  sN    !




2


r'  z/<SERVICE>/get_centersc                 C   sÞ   t ƒ }tƒ }|t j}|t j}t||ƒ}t|ƒ}|rÊ| dkrNt|t|ƒƒ}n^| dkrft|t	|ƒƒ}nF| dkr~t|t
|ƒƒ}n.| dkr–t|t|ƒƒ}n| dkr¬t|t|ƒƒ}td|›�ƒ td|iƒdfS td	d
iƒdfS d S )Nra   rb   rc   rd   re   zget_centers: respuesta=ZIDsrõ   ré   z-El usuario no posee permisos de visualizacionrô   )r   r/   r�   rf   rþ   r¹   r¼   rå   rÈ   rÉ   rÇ   rÊ   r×   rm   r   )r#  r¸   r’   r“   rÄ   rµ   Z
validacionÚ	respuestarq   rq   rr   Úget_permisos_usuarios°  s(    


r)  z,/<SERVICE>/get_data/<REGION>/<AREA>/<CENTRO>c                    sÖ  t  d¡ | dk�r~�ztƒ }|t j}| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }|}t ¡  	d¡}|› d|› d|› �}| 
||dœ¡}	|	sÌtd|› d	�ƒ td
diƒdfW S t|	dd�‰ ˆ i kròtd
diƒdfW S ‡ fdd„tˆ ƒD ƒ}
d|
dœ}t|ƒdfW S  tk
�rx } z:td|jj› d|› �ƒ td
dt|ƒ› �iƒdf W Y ¢S d }~X Y nX �nT|  ¡ dk�r’t  d| › d|› d|› d|› d�	d›d�¡ �zntƒ }|t }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }|› d|› d|› �}|› d|› d|› �}t||ƒ}t||› d�|d�}td|›d |›�ƒ t||ƒ}t|tƒ�s t  d!t|ƒ› d"�¡ d#|i}| d$¡�p®g }t|tƒ�sÀg }d%}z.|d& d' d& d( }t|d)ƒ�rð| 	d*¡}W n: t t!t"fk
�r, } zt  d+|› �¡ W 5 d }~X Y nX |d%k�rPt#| d,¡ƒ}|�rP|}|�sptd-|› d|› d|› �ƒ d }z<|�s®t|› d.�ƒ t$||ƒ}t|› d/|›�ƒ ||d0< W n4 tk
�rä } zt  d1|› �¡ W 5 d }~X Y nX t%|||d2�}t  d3|› d|› d|› d�¡ t|||d4œ–ƒdfW S  tk
�rŒ } zDt  &d|jj› d|› d�¡ td5d6|jj› d|› �iƒdf W Y ¢S d }~X Y nX �n@|  ¡ d7k�rºtd| › d8|› d|› d|› d�	d›ƒ z”tƒ }|t' }| dd¡ dd¡ ¡ }td9|›�ƒ |› d:�}td;|›�ƒ t(|||d<d=d>�}t)||ƒ}||d?œ}td@|› dA|› �ƒ t|ƒdfW S  tk
�r¶ } z<tdB|jj› d|› d�ƒ td5dCt|ƒ› �iƒdf W Y ¢S d }~X Y nX ntd
dD| › dE�iƒdFfS d S )GNzEN GET DATAra   rù   r^  rÛ   rá  ©r&  rã  úNo hay datos para el centro ú en el dia solicitadoré   úError: no hay datos del centrorú   F©Úall_day_dataú/Datos solicitados no encontrados en el servidorc                    s   g | ]}ˆ | ‘qS rq   rq   rO  ©Zlatest_datarq   rr   rÕ   ñ  s     zget_data.<locals>.<listcomp>©Z
batch_dataÚsensor_datarH  zError en get_data linea r€  úError al obtener los datos: rb   z Solicitando datos para z de  r.   z=^60Ú
Z	_metadata)Zmetadata_col_namerÀ   zCENTRO=z control_version=u   get_latest_data_ts devolviÃ³ z -> se envuelve como 'raw'Úrawrü  z --r   rò  r  rì  ú%Y-%m-%d %H:%M:%SzAdvertencia obteniendo hora: Zgenerators_comapú*No existen datos de bombas para el centro z$ debe consultar generadores antiguosz generator=Zgeneradoresz'Error obteniendo generadores antiguos: ©Únew_versionz(Nanoox: Enviados correctamente datos de )rô  rë  ru   ú$Error interno del servidor en linea re   z de zcentro_clean=Z_flux_tszcollection_name=éh  rŽ   )ÚdbÚcollection_nameZ
sensor_keyÚNÚstep)r3  rô  zflux_to_fe <_z_> : zError en get_data FLUX linea zError interno FLUX: ú	Servicio z no soportadoé”  )*Úloggerrw   r/   r„  rf  r  r   r   r‡  rì  r‘   rm   r   Ú_get_all_station_datarn  r¬   r	  r
  r  re  rs   ÚNANOOX_DATABASE_NAMErA   rB   rC   r  r  rt   r‰   r�   rÞ   ÚhasattrÚ
IndexErrorÚKeyErrorÚ	TypeErrorrD   r@   Úget_umbrales_nanooxru   ÚFLUX_DATABASE_NAMErY   rZ   )r#  rb  rc  rd  r’   r$  r§  ÚtodayrÀ   ÚdocumentÚsorted_arrayÚdict_to_sendr­   Ú	nanoox_dbÚcentro_id_nanooxÚtipo_controlÚcontrol_versionZcenter_latest_datarü  rô  ÚtsZ
hora_comapÚ	generatorrë  Zflux_dbÚcentro_cleanr>  Zhistorical_dataZresponse_payloadrq   r1  rr   Úget_dataÍ  sø    


þ4,
ý
ÿ"
ÿ
"ýü ÿþ&
û	
þ ÿþrW  r<  c           
   
   C   s  t  ¡  d¡}z´| }|jj||dœdgd�}|r8d|krDg g dœW S dd„ |d D ƒ}d	d„ |d D ƒ}d
d„ |d D ƒ}|| d… ddd… || d… ddd… || d… ddd… dœW S  tk
� rþ }	 ztd|	› d|	jj› �ƒ W 5 d}	~	X Y nX dS )aH  
    Obtiene las ultimas N mediciones de O2 y SO2 del documento correspondiente al dia de hoy.

    :param db: Instancia de la base de datos de MongoDB.
    :param bomba_id: ID de la bomba para filtrar los documentos.
    :param N: Numero de mediciones a obtener.
    :return: Diccionario con listas de valores de O2 y SO2.
    rá  )Úbomba_idrã  )rÐ   r›  ©rû  Úsensores)ÚO2ÚSO2c                 S   s(   g | ] }|  d ¡dk	rt|d  dƒ‘qS )r[  NrÙ  ©r�   Úround©rÓ   Úsrq   rq   rr   rÕ   š	  s      z+get_last_n_measurements.<locals>.<listcomp>c                 S   s(   g | ] }|  d ¡dk	rt|d  dƒ‘qS )r\  NrÙ  r]  r_  rq   rq   rr   rÕ   ›	  s      c                 S   s"   g | ]}|  d ¡dkr|d  ‘qS )Zlast_measure_sensorz	Sin datosr2  r_  rq   rq   rr   rÕ   œ	  s      Né
   )r[  r\  ÚTSúError: rù   )	r   rL  rì  rZ  r‘   r¬   rm   r	  r
  )
r=  rX  r?  Z
today_daterP  rM  Z	O2_valuesZ
SO2_valuesrb  r­   rq   rq   rr   Úget_last_n_measurements|	  s$    
þýrd  c                 C   sü   t  |¡}z²t|ƒD ]¤\}}t|| d ƒD ]Š\}}	t|	 dg ¡ƒD ]p\}
}| d¡}| d¡}|› d|› d|› d|› d|› d|› �}t| |d�}|| d | d |
  d|i¡ qDq,qW n: tk
rö } ztd|› d	|jj	› �ƒ W 5 d }~X Y nX |S )
Nrò  ró  Zip_aviotÚnombrerÛ   )rX  Zlatest_measurementsrc  rù   )
r  ÚdeepcopyÚ	enumerater�   rd  r  r¬   rm   r	  r
  )r=  rb  rc  rd  Zcenter_requested_datarf  Zidx_modZmoduloZidx_canZcanZ	idx_bombarÿ  ZaviotZ
bomba_namerX  r—  r­   rq   rq   rr   Úlatest_measurements_conditioner©	  s    


&,*rh  z3/<SERVICE>/get_latest_data/<REGION>/<AREA>/<CENTRO>c              
      s,  | dk�rt�zt ƒ }|t j}| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }|}t ¡  d¡}|› d|› d|› �}| ||dœ¡}	|	sÂt	d|› d�ƒ t
d	d
iƒdfW S t|	dd�‰ ˆ i krèt
d	diƒdfW S ‡ fdd„tˆ ƒD ƒ}
d|
dœ}t
|ƒdfW S  tk
�rn } z:t	d|jj› d|› �ƒ t
d	dt|ƒ› �iƒdf W Y ¢S d }~X Y nX �n´| dk�r(�zDt ƒ }|t }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }t||||ƒ\}}}t|||ƒ}|�st	d|› d|› d|› �ƒ i }|D ]H}| d¡d }g ||< t||ƒ}|�r t|ƒdk�r ||  |¡ �q g }| ¡ D ]}| |¡ �qvt	d|› d|› d|› d�ƒ t	d|›�ƒ t
||dœƒdfW S  tk
�r& } zBt	d|jj› d|› d�ƒ t
dd|jj› d|› �iƒdf W Y ¢S d }~X Y nX d S ) Nra   rù   r^  rÛ   rá  r*  r+  r,  ré   r-  rú   Fr.  r0  c                    s   g | ]}ˆ | ‘qS rq   rq   rO  r1  rq   rr   rÕ   å	  s     z#get_latest_data.<locals>.<listcomp>r2  rH  zError en get_latest_data linea r€  r4  rb   r8  r.   r›  r   ú Enviados correctamente datos de zformatted_modulos=©rü  Úhistorial_controlru   r;  ©r/   r„  rf  r  r   r   r‡  rì  r‘   rm   r   rD  rn  r¬   r	  r
  r  rE  Zget_center_idsZ_get_last_cand_and_bomb_datarÜ   r?   rû   rÃ   rØ   ©r#  rb  rc  rd  r’   r$  r§  rL  rÀ   rM  rN  rO  r­   rP  Zcan_idsZbomb_idsZhistorial_control_idsrü  rk  Zhistorial_control_idZaviot_idZhistorial_aviotZformatted_modulosZmodulos_datarq   r1  rr   Úget_latest_dataÁ	  sh    

þ4
 
rn  z4/<SERVICE>/get_all_day_data/<REGION>/<AREA>/<CENTRO>c              
      s  | dk�rt�zt ƒ }|t j}| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }|}t ¡  d¡}|› d|› d|› �}| ||dœ¡}	|	sÂt	d|› d�ƒ t
d	d
iƒdfW S t|	dd�‰ ˆ i krèt
d	diƒdfW S ‡ fdd„tˆ ƒD ƒ}
d|
dœ}t
|ƒdfW S  tk
�rn } z:t	d|jj› d|› �ƒ t
d	dt|ƒ› �iƒdf W Y ¢S d }~X Y nX �n¦| dk�r�z6t ƒ }|t }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }t||||ƒ\}}}t|||ƒ}|�st	d|› d|› d|› �ƒ i }|D ]H}| d¡d }g ||< t||ƒ}|�r t|ƒdk�r ||  |¡ �q g }| ¡ D ]}| |¡ �qvt	d|› d|› d|› d�ƒ t
||dœƒdfW S  tk
�r } zBt	d|jj› d|› d�ƒ t
dd|jj› d|› �iƒdf W Y ¢S d }~X Y nX d S ) Nra   rù   r^  rÛ   rá  r*  r+  r,  ré   r-  rú   Tr.  r0  c                    s   g | ]}ˆ | ‘qS rq   rq   rO  r.  rq   rr   rÕ   @
  s     z all_day_data.<locals>.<listcomp>r2  rH  zError en all_day_data linea r€  r4  rb   r8  r.   r›  r   ri  rj  z Error en get_all_day_data linea ru   r;  rl  rm  rq   r.  rr   r/  
  sf    

þ4
 
r/  z:/<SERVICE>/get_multiple_days_data/<REGION>/<AREA>/<CENTRO>c              
      sj  | dk�r �z–t ƒ }|t j}| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }|› d|› d|› �}|}g }tjdkr´tj}	t 	|	d d¡}
t 	|	d d¡}nt 
¡ }|td	d
� }
||
 d¡| d¡dœdœ}| |¡}tdt|ƒ› d|› �ƒ i ‰ |D ]L}|�rt|dd�}| ¡ D ]*\}}|ˆ k�rHg ˆ |< ˆ |  |¡ �q.�qd‡ fdd„tˆ ƒD ƒdœ}tdt|d d ƒ› d�ƒ t|ƒdfW S  tk
�rü } z:td|jj› d|› �ƒ tddt|ƒ› �iƒdf W Y ¢S d }~X Y nX nf| dk�r"td ƒ tdd iƒdfS | d!k�rDtd"ƒ tdd"iƒdfS | d#k�rftd$ƒ tdd$iƒdfS d S )%Nra   rù   r^  rÛ   r}   Ú	startDateú%d/%m/%YÚendDateé   rƒ   rá  )ú$gtez$lter*  zSolicitado z dias para el centro Tr.  c                    s   g | ]}ˆ | ‘qS rq   rq   rO  ©Zall_stations_datarq   rr   rÕ   ´
  s     z&multiple_days_data.<locals>.<listcomp>r2  z	enviando r3  r   z datosrH  z"Error en multiple_days_data linea r€  ré   r  rú   rb   z%Datos Nanoox se obtiene de otra formarc   z$Datos Scapp se obtiene de otra formard   z"Datos PSS se obtiene de otra forma)r/   r„  rf  r  r   r   rœ   r  r   rõ  r‡  r   rì  rÂ   rm   rû   rD  rà   Úextendrn  r   r¬   r	  r
  r  )r#  rb  rc  rd  r’   r$  rÀ   r§  Zday_listÚ
date_rangeÚ
start_dateÚend_daterÅ   Ú	documentsrM  Zday_dataZstation_namerf  rO  r­   rq   rt  rr   Úmultiple_days_datay
  s`    


þþ

þ2


rz  z,/<SERVICE>/new_data/<REGION>/<AREA>/<CENTRO>c              
   C   sˆ  |||f}t  ¡  ¡ }tdƒ | dk�rÞ�zvtdƒ dd„ |||fD ƒ\}}}|› d|› d|› �}|› d|› d|› �}tƒ }|t }	tj}
t|› d�ƒ t|
 ¡ ƒ |
sºt	dd	iƒd
fW S t
|
ƒ}d|
k}|rÞt|› d�ƒ nt|› d�ƒ |dk�r td|› d�ƒ t|	|
 di ¡||d� nb|dk�r`td|› d�ƒ |
 dg ¡D ]}t|	|||d� �qFn"td|› d�ƒ t	ddiƒdfW S td|||ƒ t	ddiƒdfW S  tk
�rØ } zt	ddiƒdf W Y ¢S d }~X Y nX �n¦|  ¡ dk�r:tdƒ z¬tj}tƒ }t|tƒ�r:t|||ƒ}td|||ƒ t	d|iƒdfW S t|tƒ�rŒt|||ƒ}td|||ƒ |dk�r|t	d d!iƒdfW S t	|ƒdfW S nt	dd"iƒd
fW S W n– tk
�rð } z0td#|› �ƒ t	dd$t|ƒ› �iƒd
f W Y ¢S d }~X Y nH tjk
�r6 } z&td%|› �ƒ t	dd&iƒdf W Y ¢S d }~X Y nX nJ| d'k�rltd(| › d)�ƒ t	dd(| › d)�iƒdfS t	dd*| › d+�iƒd,fS d S )-Nz>++++++++++++ENTRANDO A RX DE DATOS PREVIO A SERVICE+++++++++++rb   z4++++++++++++ENTRANDO A RX DE DATOS NANOOX+++++++++++c                 S   s$   g | ]}|  d d¡  dd¡ ¡ ‘qS )rù   r^  rÛ   )r  r   rŸ  rq   rq   rr   rÕ   ×
  s   ÿznew_data.<locals>.<listcomp>rÛ   z Json recibido:ré   r  rë   rS  z#: Datos recibidos version  ITG ANECz&: Datos recibidos version  ITG ALLWAREr  zNanoox z+: Procesando datos en formato simple (dict)rf  r9  Únestedz,: Procesando datos en formato anidado (list)z : Formato de datos no reconocidoú)Datos recibidos erroneamente por servidori¦  z)Datos recibidos exitosamente por servidorrH  úError interno del servidorrú   re   z5++++++++++++ENTRANDO A RX DE DATOS FLUXXX +++++++++++rý  Fru   zNo se pudo guardar el datou1   Formato invÃ¡lido. Se espera JSON Object o Array.u   Error ValidaciÃ³n Flux: u   Datos invÃ¡lidos: zError Mongo Flux: z&Error de persistencia en base de datos)ra   rc   rd   zDatos z se guardan de otra formarA  z no reconocidorB  )r   r‡  Ú
astimezonerm   r/   rE  r   r  rR  r   r=   r>   r�   r   r¬   re  r  rÞ   rW   r  rX   r(  r  r)   ÚPyMongoError)r#  rb  rc  rd  Ú
raw_centroÚrecibidorÀ   rQ  r’   rP  Úreceived_jsonZ	data_typeÚflag_new_versionr±  r­   Z
data_inputZids_procesadosr(  ZveZperq   rq   rr   Únew_dataÌ
  sŠ    

þ	

ý
þ*
.(
r„  z#/<SERVICE>/<REGION>/<AREA>/<CENTRO>c           	   
   C   s
  t dƒ t |||ƒ �z’tƒ }| dd¡ dd¡ dd¡ dd¡ ¡ }| dd¡ dd¡ dd¡ dd¡ ¡ }| dd¡ dd¡ dd¡ dd¡ ¡ }| dk�r:|t j}tj}|sÆtdd	iƒd
fW S | 	d¡}|sætdd	iƒd
fW S |› d|› d|› �}t dƒ t
|||ƒ t|||ƒ t d|› �ƒ tddiƒdfW S | dk�r^t dƒ tddiƒdfW S | dk�r‚t dƒ tddiƒdfW S | dk�r¦t dƒ tddiƒdfW S W n\ tk
�r } z<t d|jj› d|› d�ƒ tddt|ƒ› �iƒdf W Y ¢S d }~X Y nX dS )Nz	post pongrù   r^  rÛ   ú<ú>rg   ré   r  rë   rf  zLLEGAMOS A GUARDAR DATOSr  r  rH  rb   z%Datos Nanoox se guardan de otra formarú   rc   z$Datos Scapp se guardan de otra formard   z"Datos PSS se guardan de otra formazError en post_ping linea r€  r  zserver pong)rm   r/   r  r   r„  rf  r   r  r   r�   r!  r"  r¬   r	  r
  r  )	r#  rb  rc  rd  r’   r§  r%  r&  r­   rq   rq   rr   Ú	post_pingJ  sD    (((





0r‡  z8/<SERVICE>/generate_data_report/<REGION>/<AREA>/<CENTRO>c              
      sh  | dk�rþt dƒ tƒ }|t j}| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }| dd¡ dd¡ ¡ }|› d|› d|› �}|}tj}t 	|d d¡}	t 	|d d¡}
g }|
|	 }t
|jd	 ƒD ]"}|	t|d
� }| | d¡¡ qÂ|	|
k�r|d  dd¡}t› d|› d|› d�‰ d}nT|d  dd¡}|d  dd¡}t› d|› d|› d|› d�‰ d|› d|› d|› d�}zDt|||ˆ ƒ�r t‡ fdd„ƒ}t|dd�W S tddiƒdfW S W nF tk
�rú } z&t ||jjƒ tddiƒdf W Y ¢S d }~X Y nX nf| dk�r t dƒ tddiƒdfS | dk�rBt dƒ tddiƒdfS | dk�rdt dƒ tddiƒdfS d S ) Nra   zGENERANDO REPORTE ENVIROrù   r^  rÛ   ro  rp  rq  rŽ   rƒ   rá  r.   r¾  ú.xlsxz%./reportes/asignacion_selectoras.xlsxú./reportes/c              
      sD   zt  ˆ ¡ W n0 tk
r> } ztj d|¡ W 5 d }~X Y nX | S ©NzError al eliminar archivo©rª   Úremover¬   ru  rC  ru   ©r¤   ru   ©Úexcel_save_pathrq   rr   Úremove_fileÄ  s
     z0generate_server_data_report.<locals>.remove_fileT©Úas_attachmentré   úError generar reporterú   rb   zNanoox NO posee reporteriarc   zDatos Scapp NO posee reporteriazScapp NO posee reporteriard   zDatos PSS NO posee reporteriazPSS NO posee reporteria)rm   r/   r„  rf  r  r   r   r  r   rõ  rú  r„   r   rÃ   rì  ÚREPORTS_DIRECTORYZgenerate_report_from_serverr   r   r   r¬   r	  r
  )r#  rb  rc  rd  r’   r$  rÀ   r§  rv  rw  rx  Z
date_arrayZdeltaÚiÚdayÚdateZexcel_send_pathZi_dateZf_dater�  r­   rq   rŽ  rr   Úgenerate_server_data_report–  sV    


(


r˜  zD/<SERVICE>/generate_nanoox_report/<REGION>/<AREA>/<CENTRO>/<CONTROL>c              
      s  t | ƒ |  ¡ } | dk�rât dƒ tƒ }|t }tj}d }t|ƒ}	|› d|› d|› �}
t dt›�ƒ t 	dt›�¡ | 
¡ }t dtj›�ƒ t||tt|d�\}‰ t 	d|›�¡ t 	dˆ ›�¡ |d	k�r¤t d
ƒ d	}zŠt‡ fdd„ƒ}|d	k�r`t dƒ zˆ  d¡d }W n, tk
�r: } zt |ƒ W 5 d }~X Y nX t d|›�ƒ td|› �d	|d�W S W n> tk
�r  } ztdd|› �iƒdf W Y ¢S d }~X Y nX n<|dk�rÆt dƒ tddiƒdfS |d k�rútddiƒdfS ntdd| › d�iƒdfS tdd| › d�iƒdfS )NÚNANOOXu7   *********** Â°ENTRANDO A CREAR REPORTE NANOOX! ********rÛ   zREPORTS_DIRECTORY=zrequest.json=)Zrango_fechasZcontrol_typer�  r  Zcentro_namezret_status=z dest_path=Tzrespuesta 200c              
      sD   zt  ˆ ¡ W n0 tk
r> } ztj d|¡ W 5 d }~X Y nX | S rŠ  r‹  r�  ©Z	dest_pathrq   rr   r�    s    
 z+generate_nanoox_report.<locals>.remove_filezentramos a mandar reporter¯   r›  zrelative_file_path=z
./reportes)r’  Údownload_nameré   ú.No hay datos para generar reportes, con error éÌ   Fzrespuesta 204z"No hay datos para generar reportesr“  rú   z#No existe reporte para el servicio z al menos en esta rutarH  )rm   Úupperr/   rE  r   r  r  r”  rC  rw   r   rE   r   rÜ   r¬   r   r   )r#  rb  rc  rd  ZCONTROLr’   rP  rf  Z	file_flagZcontrolrÀ   Zcapitalized_center_nameZ
ret_statusr�  Zrelative_file_pathr­   rq   rš  rr   Úgenerate_nanoox_reportß  sZ    

û

	
.

rŸ  z9/flux/generate_report/<CENTRO>/<FECHA_INICIO>/<FECHA_FIN>c              
      sD  �zÜt d|›�ƒ t d|›�ƒ t ƒ  tj tj t¡¡}tj |d¡}tj|dd� |  dd¡ dd	¡}d
|› d|› d|› d�}tj ||¡‰ t	ƒ }|t
 }z$t |d¡ ¡ ‰t |d¡ ¡ }	W n& tk
rè   tddiƒdf Y W S X |	ˆ jd }
‡fdd„t|
ƒD ƒ}t ¡ }d|jk�r0| |d ¡ d}|D ] }t|||| gƒ}|�r8d}�q8|�sŒd| › d|› d|› d�}t|ddœƒdfW S | ˆ ¡ | ¡  tj ˆ ¡�s¾tddiƒdfW S t‡ fdd „ƒ}tˆ d|d!d"�W S  tk
�r> } z@t d#|› �ƒ d$d%l}| ¡  tdd&t|ƒ› �iƒdf W Y ¢S d%}~X Y nX d%S )'zÂ
    Endpoint actualizado con motor generate_flux_report.
    - Retorna 200 (xlsx) si hay datos.
    - Retorna 404 (JSON) si no hay datos en el rango.
    - Retorna 500 (JSON) si hay error.
    zFECHA_INICIO=z
FECHA_FIN=r¯   Tr§   rù   r^  r.   rÛ   ZReporte_Flujometros_r¾  rˆ  rá  ré   u+   Formato de fecha invÃ¡lido. Use YYYY-MM-DD.rë   rŽ   c                    s   g | ]}ˆ t |d � ‘qS )rƒ   )r   )rÓ   r•  )rw  rq   rr   rÕ   j  s     z.download_flux_report_range.<locals>.<listcomp>ZSheetFz(No se encontraron datos para el centro 'z' entre z y r   ZDATA_NOT_FOUND)ré   Z
error_coderB  z-Error interno: El archivo no se pudo generar.rú   c              
      sP   zt j ˆ ¡rt  ˆ ¡ W n0 tk
rJ } ztd|› �ƒ W 5 d }~X Y nX | S )Nz#Error eliminando archivo temporal: )rª   r›   r  rŒ  r¬   rm   r�  )Úfilepathrq   rr   r�  Š  s     z/download_flux_report_range.<locals>.remove_filezAapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet)r’  r›  Zmimetypeu'   Error crÃ­tico en descarga Flujometro: r   NúError interno del servidor: ) rm   rª   r›   ÚdirnameÚabspathÚ__file__rÍ  r«   r  r/   rK  r   rõ  r—  r(  r   r„   rú  ÚopenpyxlZWorkbookZ
sheetnamesrŒ  r[   ZsaveÚcloser  r   r   r¬   Ú	tracebackÚ	print_excr  )rd  ZFECHA_INICIOZ	FECHA_FINZbase_dirZreports_dirrV  Úfilenamer’   r=  rx  Zdays_betweenZ
dates_listÚwbZ
data_foundÚdate_objZhas_data_dayrp   r�  r­   r§  rq   )r   rw  rr   Údownload_flux_report_rangeG  s^    
	ür¬  z>/<SERVICE>/generate_historical_report/<REGION>/<AREA>/<CENTRO>c              
      sx  t ƒ }|t }|  ¡ } tj}|› d|› d|› �}t› d�}|› d�}	t||	 ƒ‰ td|	›�ƒ tdˆ ›�ƒ td|›�ƒ t||||	ƒ}
td|
›�ƒ |
dk�r0td	ƒ zFt	‡ fd
d„ƒ}|
rÔt
d|› d�dd�W S tdd|› �iƒdfW S W n> tk
�r, } ztdd|› �iƒdf W Y ¢S d }~X Y nX nD|
dk�rRtdƒ tddiƒdfS |
d k�rttdƒ tddiƒdfS d S )NrÛ   r.   z-reporte_historial.xlsxú
file_name=úfile_remove=úexcel_save_path=zreporte_status=TzHay datos y se genera excelc              
      sD   zt  ˆ ¡ W n0 tk
r> } ztj d|¡ W 5 d }~X Y nX | S rŠ  r‹  r�  ©Zfile_removerq   rr   r�  Â  s
     z/generate_historical_report.<locals>.remove_filer‰  r‘  ré   rœ  r�  Fz!NO Hay datos y NO se genera excelz-No hay datos para generar reportes, con errorúError servidorr“  rú   )r/   rE  rž  r   r  r”  r  rm   Zgen_reporte_historialr   r   r   r¬   ©r#  rb  rc  rd  r’   rP  rf  rÀ   r�  Ú	file_nameZreporte_statusr�  r­   rq   r°  rr   Úgenerate_historical_report¢  s:    


.

r´  z=/<SERVICE>/generate_generator_report/<REGION>/<AREA>/<CENTRO>c              
      s`  t ƒ }|t }|  ¡ } tj}tdƒ |› d|› d|› �}t|ƒ}t› d�}|› d�}	t||	 ƒ‰ td|	›�ƒ tdˆ ›�ƒ td|›�ƒ t	||||	ƒ}
|
dk�rtd	ƒ z&t
‡ fd
d„ƒ}td|› d�dd�W S  tk
�r } ztdd|› �iƒdf W Y ¢S d }~X Y nX nJ|
dk�r:tdƒ tdd|› �iƒdfS |
d k�r\tdƒ tddiƒdfS d S )NzD###########ENTRANDO A GENERAR REPORTE GENERADOR ####################rÛ   r.   z-reporte_generador.xlsxr­  r®  r¯  TzHabian datosc              
      sD   zt  ˆ ¡ W n0 tk
r> } ztj d|¡ W 5 d }~X Y nX | S rŠ  r‹  r�  r°  rq   rr   r�  ó  s
     z.generate_generator_report.<locals>.remove_filer‰  r‘  ré   rœ  r�  Fz,No habian datos en la fecha, respondemos 204r±  r“  rú   )r/   rE  rž  r   r  rm   Úconvertir_mal_menorr”  r  Zgen_reporte_generadoresr   r   r¬   r   r²  rq   r°  rr   Úgenerate_generator_reportØ  s8    


.

r¶  z/crear_usuarioc            
      C   s  t ƒ } | t j}| t j}tƒ }tj}t|tƒr6|g}g }|D ]Î}zht	d|›�ƒ t
|||ƒ\}}|dkr~t||| d¡dƒ | | d¡|t|dƒrž| ¡ n|dœ¡ W q> tk
�r
 }	 z@t	d| d¡› d|	› �ƒ | | d¡d	d
t|	ƒ› �dœ¡ W 5 d }	~	X Y q>X q>td|iƒdfS )NzIntentando crear: data_user=rõ   rŒ   Zadd_userÚget_json)r¸   Úestador?  r÷   rø   rú   úError inesperado: Ú
resultadoséÏ   )r/   r�   rf   r…  r   r   r  r  r  rm   r  r1   r�   rÃ   rF  r·  r¬   r  r   )
r’   r“   r�  r  rf  rº  r  r?  Zcodigo_estador­   rq   rq   rr   Úapi_crear_usuario  s@    


   ÿýýr¼  z!/delete_user/<user>/<delete_user>c              
   C   s,  t ƒ }|t j}|t j}| }|}td|› d�ƒ td|› d�ƒ | d|i¡}| d|i¡}|d }	|d }
t|	|
ƒ�rzXt||ƒ}|dkr¶t|||dƒ t	dd	|› d
�iƒdfW S t	dd	|› d�iƒdfW S W nB t
k
�r } z"t	ddt|ƒ› �iƒdf W Y ¢S d}~X Y nX nt	ddiƒdfS dS )aB  
    Endpoint para eliminar un usuario existente en la base de datos.
    
    Parametros:
    - username (str): Nombre de usuario del usuario a eliminar.

    Retorna:
    - Un objeto JSON con el resultado de la operacion y un codigo de estado HTTP.
    
    Ejemplo de uso:
    DELETE /delete_user/nombre_de_usuario
    zusuario_actual: ú 
zusuario_delete :rŒ   rç   rH  Údelete_userré   r¶   rG  rI  rë   r¹  rú   Nrö   )r/   r�   rf   r…  rm   r‘   r1  rM  r1   r   r¬   r  )r•   r¾  r’   r“   r�  r  Zusuario_deleter  Zusuario_delete_infor  Z
cargo_editZstatus_coder­   rq   rq   rr   r¾  5  s*    


2r¾  z/obtener_usuariosc               
   C   sz   z8t ƒ } | t j}| i dddœ¡}t|ƒ}t|ƒdfW S  tk
rt } ztdt|ƒdœƒdf W Y ¢S d }~X Y nX d S )Nr   )rÐ   ræ   rH  z%Error al obtener la lista de usuarios)ré   ru   rú   )r/   r�   rf   rÂ   rÞ   r   r¬   r  )r’   r“   rÜ  Zlista_usuariosr­   rq   rq   rr   Úapi_obtener_usuariosi  s    
r¿  z/editar_usuariosc            !      C   s>  t ƒ } tƒ }|t j}|t j}tj}| d¡}t|t	ƒr>|sNt
ddiƒdfS | d| i¡}|spt
ddiƒdfS |d }|d	kr�t
dd
iƒdfS g }|D �]’}	|	 d¡}
|	 d¡}d|
i}|
rÈt|tƒsä| dddœ¡ | |¡ q˜| d|
i¡}|�s| dddœ¡ | |¡ q˜t||d ƒ�s@| dddœ¡ | |¡ q˜�z’t||
||d� | d¡}| d¡}|�r¶|�r¶g }| ¡ D �]\}}| ¡ D ]ú\}}| ¡ D ]æ\}}d}| ¡ D ]0\}}t|tƒ�r¶| d¡dk�r¶d} �qè�q¶|�r¢z^| d¡}t|ƒdk�rJ|d  ¡ }|d  ¡ }|d  ¡ }|› d|› d|› �}| |¡ W n8 tk
�r„ } ztd|› d|› �ƒ W 5 d}~X Y nX �q¢�q’�q€|�r¶td |
› d!|› �ƒ t||ƒ t|| |
d"ƒ | dd#i¡ W nL tk
�r  }  z,td$|
› d| › �ƒ | dt| ƒdœ¡ W 5 d} ~ X Y nX | |¡ q˜t
d%|iƒd&fS )'uð  
    Permite editar multiples usuarios, incluyendo transformacion de permisos simplificados para Jefe Area y Jefe Region.
    {
    "edits": [
        {
        "username": "usuarioA",
        "updates": {
            "correo": "nuevoA@ejemplo.com",
            "cargo": "Jefe Area",
            "permisos": {
            "loslagos": {
                "chiloe": {
                "chalihue-chiloe-loslagos": {
                    "enviro": { "status": true },
                    "nanoox": { "status": false },
                    "pss":    { "status": true },
                    "scapp":  { "status": true }
                }
                }
            }
            }
        }
        }
        // â€¦otros objetos de edicionâ€¦
    ]
    }
    Úeditsru   z&Se requiere un array 'edits' no vacio.rë   rŒ   zEditor no encontrado.rB  rç   rð   zNo posee permisos para editar.é“  rU  zPayload invalido.)r¢   rp   rN  ZdeniedzRango insuficiente.)rV  Ú	fcm_tokenrµ   Fr¢   TrÛ   rï   r   rŽ   rÙ  u    Error formateando tÃ³pico rø   Nz [AUTO-SUB] Suscribiendo z a: Z	edit_userÚokzError editando usuario Úresultsr»  )r   r/   r�   rf   r…  r   r  r�   r  rÞ   r   r‘   r  r  rÃ   r  rY  rà   rÜ   rû   r   r¬   rm   Zsuscribir_token_a_topicosr1   r  )!Zeditorr’   rT  Zhistory_colZbodyrÀ  rV  rW  rÄ  ZeditrŒ   rU  r±  Ztarget_inforÂ  rX  Ztopicos_a_suscribirrä   r  r  r/  Z
centro_rawr  Z	se_activoZsrvrf  ÚpartsZc_nameZa_nameZr_nameZtopic_formateadoZe_topicr­   rq   rq   rr   Úapi_editar_usuarios_multiples~  s�    












2
ü&rÆ  z/ediciones_usuarioc            	      C   s²   t ƒ } tƒ }|t j}g }dddddœ}| d| i¡}|d }| ¡ D ]4}t||d ƒrF| d|d i|¡}| |d ¡ qF|d k	r–td|›�ƒ |S t	dd| › d�iƒd	fS d S )
Nr   ©rÐ   ræ   r  r½   rŒ   rç   zlista_editables=ré   rÛ  z no tiene usuarios editablesrô   )
r   r/   r�   rf   r‘   rÂ   r  rÃ   rm   r   )	rŒ   r’   r“   Zlista_editablesÚ
proyeccionr  r  r¸   rº  rq   rq   rr   Úusuarios_a_editar  s    
rÉ  z	/get_linkc               
      sæ  t dƒ tj‰ t dˆ ›�ƒ ddg} t‡ fdd„| D ƒdƒ}|sPtdd	iƒd
fS ˆ | }tƒ }|d d }|dkr‚| d|i¡}n| d|i¡}|s¬tdd|› d�iƒdfS | d¡}| d¡}|sÔtddiƒdfS tdd�}t	||ƒ}	t dƒ t
|	ƒ}
|
 d¡}t ¡ | }z.t dƒ | d|id||dœi¡ t dƒ W nP tk
�rŒ } z0t d|› d|jj› �ƒ tddiƒdf W Y ¢S d}~X Y nX d}|› d|	› �}t d|› �ƒ t dƒ t|||ƒ t d |› d!|› �ƒ td"d#iƒd$fS )%u¤   
    A partir del nombre de usuario o correo, obtiene su email desde la DB y 
    envÃ­a un e-mail con un token para restablecer la contraseÃ±a en el Frontend.
    zEntrando a get_link!údata=rŒ   rè   c                 3   s   | ]}ˆ   |¡r|V  qd S rv   r2  rO  ©rf  rq   rr   r  .  s     
 z!reset_password.<locals>.<genexpr>NÚErrorz#Ni username ni correo tienen valor.rë   rf   zEl usuario/correo z no se encuentra registrado.rB  z'El usuario no posee un correo asociado.rŽ   ©ZhourszDecodificando TOKENrˆ   zInsertando JTI en dbrQ  ©Ú	reset_jtiZreset_expires_atz><> JTI en DBzError al insertar JTI: rù   zServer Internal Error.rú   z!https://ventisqueros.itgchile.comz/ResetPassword/z"Enlace generado para el frontend: zEntrando a enviar mailz Enlace enviado a usuario/correo r.   ÚMessageu/   Enlace enviado para restablecer la contraseÃ±a.rH  )rm   r   r  r«  r   r/   r‘   r�   r   rw  ry  r   r‡  rS  r¬   r	  r
  r7   )ZclavesZ	seleccionrÚ   r’   r“   r•   rè   rŒ   Zexpiresr¾   rx  rˆ   Z
expires_atr­   Zfrontend_domainÚlinkrq   rË  rr   Úreset_password!  sZ    




þþ&rÒ  z/update_passwordc            
   
   C   s"  t j} |  d¡}|  d¡}|r"|s2tddiƒdfS z¤t|ƒ}| d¡}| d¡}tƒ }|d d }| d	|i¡}|s†tdd
iƒdfW S | d¡|kr¦tddiƒdfW S | d	|id|idddœdœ¡ tddiƒdfW S  tk
�r }	 z&t	d|	› �ƒ tddiƒdf W Y ¢S d }	~	X Y nX d S )Nr¾   Únew_passwordrÌ  u)   Faltan datos (token o nueva contraseÃ±a).rë   rŠ   rˆ   rf   rŒ   rN  rB  rÏ  u,   Este enlace ya fue utilizado o es invÃ¡lido.rô   ræ   r^  rÎ  ©rQ  rÚ  rÐ  u%   ContraseÃ±a actualizada exitosamente.rH  zError al actualizar password: u   Token invÃ¡lido o expirado.)
r   r  r�   r   ry  r/   r‘   rS  r¬   rm   )
rf  r¾   rÓ  rx  rŒ   rˆ   r’   r“   r•   r­   rq   rq   rr   Úupdate_passwordq  s4    



þþrÕ  z/ResetPassword/<token>c                 C   s”  zt | ƒ}td|›�ƒ W n$ tk
r>   tddiƒdf Y S X | d¡sZtddiƒdfS | d¡}tƒ }|d }|j}|j}| |d	t	 
¡ id
œ¡}td|›�ƒ |r°|dkrÈtdƒ tddiƒdfS |d }|sätddiƒdfS tjdd�pôtj}	|	 d¡}
|
�stddiƒdfS | d|idt|
ƒiddd
œdœ¡}|jdk�rVtddiƒdfS tdƒ t||ddƒ td|› d�ƒ tdd|› d�iƒd fS )!uÐ   
    Ruta dinamica para ingresar nueva contraseÃ±a solo si el token de acceso es valido (nombre, clave_secreta y duracion).
    De modificar exitosamente la clave, genera un log en historial de usuarios.
    zreset decoded=rÌ  zToken invalido o expirado.rÁ  rr  z&Token no valido para restablecimiento.rˆ   rf   z$gtrÎ  zuser=NzToken ya usado o expirado.rŒ   zNo hay datos del usuario.rB  T)Zsilentræ   u!   Se requiere la nueva contraseÃ±a.i–  r^  rÔ  r   u    Error al actualizar contraseÃ±a.rú   u5   Se ha modificado exitosamente la contraseÃ±a en la DBZrenew_passwordu6   ContraseÃ±a actualizada correctamente para el usuario r   rÐ  rH  )ry  rm   r¬   r   r�   r/   rf   r…  r‘   r   r‡  r   r·  ZformrS  r%   r•  r1   )r¾   rx  rˆ   r’   Úusers_dbr“   r�  r•   rŒ   rf  rÓ  r—  rq   rq   rr   Úreset_tokenž  sN    


þ

ÿþ	r×  z/get_users_historical_logsc                  C   s  t ƒ } | d }|j}tj dd¡}tj d¡}tj d¡}tj d¡}i }|rb| ¡ dkrb||d< |rºzt |d¡}W n$ tk
rš   t	dd	iƒd
f Y S X |t
dd� }	||	dœ|d< n²|sÄ|�rli }
|�rzt |d¡}W n& tk
�r   t	ddiƒd
f Y S X ||
d< |�r^zt |d¡}W n& tk
�rJ   t	ddiƒd
f Y S X |t
dd� |
d< |
�rl|
|d< tdt|ƒ›�ƒ t| |ddi¡ dd¡ƒ}td|›�ƒ g }|D ]N}tdt|ƒ›�ƒ d|k�ròt|d tƒ�rò|d  d¡|d< | |¡ �q°t	|ƒdfS )a  
    Endpoint to fetch user action logs by specific date, date range, and type.

    Query parameters:
    - type: one of ['edit_user', 'add_user', 'delete_user', 'renew_password'] or 'all' (default 'all')
    - date: single day in 'YYYY-MM-DD' format (optional)
    - start_date: beginning of range in 'YYYY-MM-DD' format (optional)
    - end_date: end of range in 'YYYY-MM-DD' format (optional)

    Examples:
    /logs?date=2025-06-19&type=edit_user
    /logs?start_date=2025-06-01&end_date=2025-06-10&type=all
    rf   r‰   r  r—  rw  rx  rá  ru   z#Invalid date format, use YYYY-MM-DDrë   rŽ   rƒ   )rs  ú$ltz)Invalid start_date format, use YYYY-MM-DDrs  z'Invalid end_date format, use YYYY-MM-DDrØ  zlist(query)=rÐ   r   zcursor=z
list(doc)=z%Y-%m-%dT%H:%M:%SrH  )r/   r…  r   Úargsr�   re  r   rõ  r(  r   r   rm   rÞ   rÂ   rû  r  rì  rÃ   )r’   rÖ  r�  Z
type_paramZdate_strZ	start_strZend_strrÅ   r«  Znext_dayZdate_filterZ	start_objZend_objrÖ   rÄ  rÔ   rq   rq   rr   Úget_logsã  sV    
rÚ  z$/report_gps/<REGION>/<AREA>/<CENTRO>c              
   C   sŽ  zXt jdd�}td|›�ƒ | ¡ }| ¡ }|  ¡ } |› d|› d| › �}td|›�ƒ W n< tk
r” } ztdd|› �iƒdf W Y ¢S d }~X Y nX | d	¡}| d
¡}|r¾|d ks¾|d krÎtddiƒdfS zt|ƒ}t|ƒ}W n& tk
�r   tddiƒdf Y S X ||t	 
¡ dœ}tƒ }	|	t }
|
d }| d|idd|ii¡}|jdk�rjtdd|› �iƒdfS td|› �ƒ tdd|› �iƒdfS )NT)ÚforcerÊ  rÛ   ú
centro_id=rÌ  zJSON invalido rë   r}  r~  z8Faltan parametros: centro_id, lat y lon son obligatoriosz%lat y lon deben ser valores numericos)r}  r~  r  rþ   rÀ   rQ  zgps_coordinates.autor   zNo existe documento con ID rB  z&Datos de GPS actualizados para centro rÐ  rH  )r   r·  rm   re  r¬   r   r�   Úfloatr(  r   r‡  r/   r�   rS  Úmatched_count)rb  rc  rd  rf  rÀ   r­   r}  r~  Zcoordinatesr’   rÖ  rÄ   r—  rq   rq   rr   Úreport_position-  sD    ,

ý
þrß  z/centros/detectadosc                  C   s„   t ƒ j} tƒ }| j d|iddi¡p&i }| d¡dkrPt d|¡ tdd�dfS t| j	 
d	d
didddiigdœddi¡ƒ}t|ƒS )NrŒ   rç   rŽ   r"  z:centros.detectados_rechazado motivo=sin_permiso usuario=%sÚsin_permiso©ZcodigorÁ  r|  Úestado_altaZ	pendienteú"autodeteccion.publicacion_completaz$neT)ÚorigenrË   rÐ   r   )r/   rf   r   r‘   r�   r   rt   r   rÞ   rþ   rÂ   )r=  rŒ   r¸   Ú
documentosrq   rq   rr   Úcentros_detectadosc  s    
 
ÿþræ  z)/centros/detectados/<centro_id>/confirmarc                 C   s¼  t ƒ j}tƒ }|j d|iddi¡p&i }| d¡dkrRt d| |¡ tdd�dfS �z¸tƒ ��T |j	 | d	d
œ¡}|s t d| |¡ tdd�dfW  5 Q R £ W S | di ¡ d¡rØt 
d| |¡ tdd�W  5 Q R £ W S t||tƒ |  d¡\}}}d|› d|› d| › �}dd„ |j ddddidœd|› �dddidœdddd|› d|› �dddidœidd|› d|› �d d!iid|› d|› �dddidœigd"œgid#di¡D ƒ}	| d$¡d%k�rê|j	 d#|d# id&d$d%ii¡ t 
d'| |t|	ƒ¡ nt 
d(| |t|	ƒ¡ t|g|ƒ d)d„ |j d#d*|	i|d d!iiddi¡D ƒ}
|
�rtt d+| |d, tt|
ƒ¡¡ td-d�d.fW  5 Q R £ W S |j	 d#|d# id&d|t ¡ d/œi¡ t 
d0| |t|	ƒ¡ W 5 Q R X zt|j|| d1ƒ W n4 tk
�r  } zt d2| ||¡ W 5 d }~X Y nX tdd�W S  tk
�r>   t d3| |¡ td4d�d.f Y S  ttfk
�r† } z&t d5| ||¡ td4d�d.f W Y ¢S d }~X Y n2 tk
�r¶   t d6| |¡ td4d�d.f Y S X d S )7NrŒ   rç   rŽ   r"  zCcentros.confirmar_rechazado motivo=sin_permiso centro=%s usuario=%srà  rá  rÁ  r|  )rÀ   rä  zEcentros.confirmar_rechazado motivo=no_encontrado centro=%s usuario=%sÚcentro_no_encontradorB  ZautodeteccionZpublicacion_completazFcentros.confirmar_sin_cambios motivo=ya_publicado centro=%s usuario=%sT)rÃ  rÛ   r’  r   c                 S   s   g | ]}|d  ‘qS ©rÐ   rq   ©rÓ   Úurq   rq   rr   rÕ   ˆ  s     z.confirmar_centro_detectado.<locals>.<listcomp>rµ   Úobjectú$typeZarray)rì  z$notrË   rò   ró   r“  F)rç   rË   rÐ   râ  Z
confirmadorQ  uR   centros.confirmado centro=%s usuario=%s jefes_elegibles=%d (publicaciÃ³n iniciada)zEcentros.publicacion_reintento centro=%s usuario=%s jefes_elegibles=%dc                 S   s   g | ]}|  d ¡‘qS rØ  r2  ré  rq   rq   rr   rÕ   ™  s     rÌ   zPcentros.publicacion_incompleta centro=%s usuario=%s faltan=%s (reintento manual)rÅ  Zpublicacion_incompletaé÷  )rã  Zconfirmado_porZconfirmado_enz/centros.publicado centro=%s usuario=%s jefes=%dZconfirm_detected_centerzHcentros.auditoria_fallida accion=confirmar centro=%s usuario=%s error=%szIcentros.confirmar_pospuesto motivo=exclusion_ocupada centro=%s usuario=%sÚcentro_reintentarz7centros.confirmar_fallido centro=%s usuario=%s error=%sz.centros.confirmar_fallido centro=%s usuario=%s)r/   rf   r   r‘   r�   r   rt   r   r   rþ   rs   r   r˜  rÜ   rÂ   rS  rû   rÐ  rÍ  Úmapr  r   r‡  r1   r…  r¬   ÚBlockingIOErrorÚOSErrorÚRuntimeErrorÚ	exception)rÀ   r=  rŒ   r¸   rÔ   r¾  r  rä   r›   Z	elegiblesZ	faltantesru   rq   rq   rr   Úconfirmar_centro_detectador  s¢    
    þþþø	  ÿ  ÿ ÿ  ÿ þ
  ÿ"rô  c                 C   sž  | j }|d }|j  d|iddi¡p&i }| d¡dkrRt d||¡ tdd�d	fS �zâtƒ ��v |j |d
 ddœ¡}|s¤t d||¡ tdd�dfW  5 Q R £ W S | d¡\}}}	d|	› d|› d|› �}
|
ddii}|j  	|d|
dii¡j
}|j d|i¡j}|j  |¡�s |j d|i¡�rJt d||¡ tdd�dfW  5 Q R £ W S t ¡ D ]V}zt| | t |	||ƒ W n4 tk
�r¤ } zt d|||¡ W 5 d }~X Y nX �qR|j d
|d
 i¡ t d||||¡ W 5 Q R X zt|j||dƒ W n4 tk
�r" } zt d|||¡ W 5 d }~X Y nX td|› d�d �W S  tk
�rh   t d!||¡ tdd�df Y S  tk
�r˜   t d"||¡ tdd�df Y S X d S )#NrÀ   rŒ   rç   rŽ   r"  zAcentros.borrado_rechazado motivo=sin_permiso centro=%s usuario=%srà  rá  rÁ  rÐ   r|  )rÐ   rä  zCcentros.borrado_rechazado motivo=no_encontrado centro=%s usuario=%srç  rB  rÛ   r’  r   r“  TrÚ  r^  zzcentros.borrado_incompleto centro=%s usuario=%s motivo=permisos_o_estados_persisten (el ciclo se conserva para reintentar)rî  rí  zJcentros.borrado_emails_fallido centro=%s base=%s error=%s (mejor esfuerzo)zPcentros.borrado_automatico centro=%s usuario=%s permisos_retirados=%d estados=%dÚdelete_centerzEcentros.auditoria_fallida accion=borrar centro=%s usuario=%s error=%súEl centro 'ú!' ha sido eliminado exitosamente.)ré   zGcentros.borrado_pospuesto motivo=exclusion_ocupada centro=%s usuario=%sz,centros.borrado_fallido centro=%s usuario=%s)rf   r‘   r�   r   rt   r   r   rþ   rÜ   r  r•  r†  Zdelete_manyrK  Zcount_documentsr0   rØ   r9   r  r¬   rJ  rs   r1   r…  rð  ró  )r’   Ú	documentorŒ   r=  rÀ   r¸   rÔ   r  r  rä   r›   rL  Z	retiradosr†  rý   ru   rq   rq   rr   Úeliminar_automaticoµ  sl    
  ÿ  ÿ   ÿ  ÿrù  z/crear_centroc               
      sn  t dƒ tƒ } tƒ }|t }tj}t|tƒrXtdd„ |D ƒƒrXt	 
d| ¡ tdd�dfS t d|› �ƒ z²t|| |ƒ d	d
„ |j dddd„ |D ƒidœddi¡D ƒ‰ ‡ fdd„|D ƒ}ˆ rÒt	 
dd tˆ ƒ¡| ¡ |sætdd�dfW S t|ƒ t||ƒ tƒ  t||ƒ tddiƒdfW S  tk
�rh } z0t d|› d|jj› �ƒ tddiƒdf W Y ¢S d }~X Y nX d S )NzENTRANDO A CREAR CENTRO!c                 s   s   | ]}t |ƒV  qd S rv   )r	   rŸ  rq   rq   rr   r  ì  s     z#api_crear_centro.<locals>.<genexpr>zAcentros.alta_manual_rechazada motivo=campos_reservados usuario=%sr	   rá  rë   zdata_centros: c                 S   s   h | ]}|d  ’qS rÑ   rq   ©rÓ   rZ  rq   rq   rr   Ú	<setcomp>õ  s     z#api_crear_centro.<locals>.<setcomp>r|  rÌ   c                 S   s   g | ]}|d  ‘qS rÑ   rq   rú  rq   rq   rr   rÕ   ö  s     z$api_crear_centro.<locals>.<listcomp>)rä  rÀ   rÀ   rŽ   c                    s   g | ]}|d  ˆ kr|‘qS rÑ   rq   rú  ©Zautomaticosrq   rr   rÕ   ÷  s      zKcentros.alta_manual_excluida motivo=centro_automatico centros=%s usuario=%srÅ  Zcentro_automaticorî   ré   zOperacion exitosarH  rc  rù   r�  rú   )rm   r   r/   r�   r   r  r  rÞ   rª  r   rt   r   r�  rþ   rÂ   rÍ  rn  r™  rÐ  rG   r  r¬   r	  r
  )rŒ   r’   r‹  r®  r­   rq   rü  rr   Úapi_crear_centroã  s>     ÿ ÿ

rý  z/obtener_centrosc                  C   sÂ   t ƒ } | t }|j}|j}tdƒ tƒ }| d|i¡}|d }ddddddœ}|dkrntdd|› d	�iƒd
fS t| d|i|¡d ƒ}g }	| 	dd|iiddi¡D ]}
|	 
|
¡ q¢t|	ƒdfS d S )NzENTRANDO A CENTROS EDITABLESrŒ   rç   r   )rÐ   ræ   Zrolr  r½   )r"  rj   ró   rò   ré   rÛ  z no posee permisos de edicionrú   rµ   rÀ   rÌ   rÐ   rH  )r/   r�   rf   rþ   rm   r   r‘   r   r×  rÂ   rÃ   )r’   r‹  r“   rÄ   rŒ   r  r  rÈ  r/  Zciclos_centror  rq   rq   rr   Úcentros_editables  s     rþ  z/editar_centro/<centro_id>c              
   C   s   t dƒ tƒ }tƒ }|t }|j}|j}tj}t|ƒrRt	 
d| |¡ tdd�dfS t d|›�ƒ zbt|d| i|ƒ t||| dƒ tƒ  d	|krªd|krž| |d< t||gƒ td
d| › d�iƒdfW S  tk
�r } z8t d|› d|jj› �ƒ td
d| › d�iƒdf W Y ¢S d }~X Y nX d S )NzENTRANDO A EDITAR CENTROzGcentros.edicion_rechazada motivo=campos_reservados centro=%s usuario=%sr	   rá  rë   zdatos_centro=rÀ   Zedit_centerrh   ré   r‚  z se ha editado correctamenterH  zError editar_centro: rù   z< no se ha logrado editar en este momento, intente nuevamenterô   )rm   r   r/   r�   r…  rþ   r   r  r	   r   rt   r   rÖ  r1   rG   r  r¬   r	  r
  )rÀ   rŒ   r’   r‹  r�  rÄ   Zdatos_centror­   rq   rq   rr   Úeditar_centro)  s.    rÿ  z/eliminar_centro/<centro_id>c                 C   s  t ƒ }tƒ }|t }|j}|j}|j}|j}| d| i¡}|rX| d¡dkrXt	|||ƒS |d krxt
dd| › d�iƒdfS �zH| d| i¡}	|	jdk�r®t|| ƒ t|| ƒ z¨|  d	¡}
t|
ƒd
k�rP|
d }|
d }d	 |
d d… ¡}t ¡ D ]`\}}z|| t }t||||ƒ W qî tk
�rL } ztd|› d|› �ƒ W 5 d }~X Y qîX qîW n2 tk
�r„ } ztd|› �ƒ W 5 d }~X Y nX t||| dƒ t
dd| › d�iƒdfW S t
ddiƒdfW S W nF tk
�r } z&td|› �ƒ t
ddiƒdf W Y ¢S d }~X Y nX d S )NrÀ   rä  r|  ré   r‚  z
 no existerú   r   rÛ   rï   r›  rœ  z&Warn: No se pudo borrar email list de rø   z)Error parseando ID para eliminar emails: rõ  rö  r÷  rH  z(Error al eliminar el documento principalz!Error critico eliminando centro: r}  )r   r/   r�   r…  rþ   rf   r†  r‘   r�   rù  r   rJ  rK  rÝ  rà  rÜ   rû   rÍ  r0   rà   r  r9   r¬   rm   r1   )rÀ   rŒ   r’   r‹  r�  rÄ   r“   rŽ  rø  r?  r³  r  r  Zc_nombreZnombre_servicior  Zservice_collectionZex_servZex_parser­   rq   rq   rr   Úeliminar_centroO  sJ    


, r   c           	         s  |dkr| t  j}n|dkr&| t j}td|› �ƒ z| |¡ tdƒ W nÊ tjk
�r } z¨tdƒ |j}| dg ¡}dd„ |D ƒ‰ ˆ �rtd	ˆ › �ƒ ‡ fd
d„|D ƒ}|rüz| |¡ tdƒ W n0 tjk
rø } ztd|jƒ W 5 d }~X Y nX ntdƒ W 5 d }~X Y nX d S )Nrg   r™  zalertas_desde_local: ú#Documentos insertados exitosamente.ú8Error en la insercion en bloque, manejando duplicados...rÊ  c                 S   s$   g | ]}|d  dkr|d d ‘qS ©Úcodeiø*  ÚoprÐ   rq   ©rÓ   ru   rq   rq   rr   rÕ   ¼  s      z+guardar_alertas_activas.<locals>.<listcomp>úIDs duplicados encontrados: c                    s   g | ]}|d  ˆ kr|‘qS rè  rq   rÒ   ©Zduplicated_idsrq   rr   rÕ   Á  s      ú-Documentos restantes insertados exitosamente.ú.Error en la insercion en bloque (segunda vez):úGNo hay documentos restantes por insertar despues de filtrar duplicados.)	r„  ÚalertasrE  rm   Úinsert_manyr)   r+   rÎ  r�   )	r’   Úservicer  Ú	coleccionÚbweÚerror_detailsÚwrite_errorsry  Ú	bwe_innerrq   r  rr   Úguardar_alertas_activasª  s.    


 r  c           	         s  |dkr| t  j}n|dkr&| t j}td|› �ƒ z| |¡ tdƒ W nÊ tjk
�r } z¨tdƒ |j}| dg ¡}dd„ |D ƒ‰ ˆ �rtd	ˆ › �ƒ ‡ fd
d„|D ƒ}|rüz| |¡ tdƒ W n0 tjk
rø } ztd|jƒ W 5 d }~X Y nX ntdƒ W 5 d }~X Y nX d S )Nrg   r™  zfallas_desde_local: r  r  rÊ  c                 S   s$   g | ]}|d  dkr|d d ‘qS r  rq   r  rq   rq   rr   rÕ   Þ  s      z*guardar_fallas_activas.<locals>.<listcomp>r  c                    s   g | ]}|d  ˆ kr|‘qS rè  rq   rÒ   r  rq   rr   rÕ   ã  s      r	  r
  r  )	r„  Úalertas_fallasrE  rm   r  r)   r+   rÎ  r�   )	r’   r  Úfallasr  r  r  r  ry  r  rq   r  rr   Úguardar_fallas_activasË  s.    


 r  c                    sz  |dkr| t  j}n|dkr&| t j}td|› �ƒ td|› �ƒ |r�|d }|d }|d }|d d	 }t|||d
œdd||dœiidd�g}	z| |	¡}
tdƒ W nÎ tjk
�rt } z¬tdƒ |j}| 	dg ¡}dd„ |D ƒ‰ ˆ �rdtdˆ › �ƒ ‡ fdd„|D ƒ}|�r\z| 
|¡ tdƒ W n2 tjk
�rX } ztd|jƒ W 5 d }~X Y nX ntdƒ W 5 d }~X Y nX d S )Nrg   r™  znotas_desde_local: úcentro: rã  rô  rý  Znotar`  )rã  rÀ   rX  ú$pushÚnotas)rô  r`  Tr”  r  r  rÊ  c                 S   s$   g | ]}|d  dkr|d d ‘qS r  rq   r  rq   rq   rr   rÕ   5  s      z!guardar_notas.<locals>.<listcomp>r  c                    s   g | ]}|d  ˆ kr|‘qS rè  rq   rÒ   r  rq   rr   rÕ   :  s      r	  r
  r  )r„  r  rE  rm   r'   rˆ  r)   r+   rÎ  r�   r  )r’   r  rÀ   r  r  rã  rô  rX  Z
comentariorî  r—  r  r  r  ry  r  rq   r  rr   Úguardar_notas  sR    

þÿÿöÿ

 r  c                 C   s"   |   d¡}dd„ |D ƒ}d |¡S )NrÛ   c                 S   s   g | ]}|  ¡ ‘qS rq   )r   )rÓ   Zpalabrarq   rq   rr   rÕ   F  s     z)capitalizar_centro_id.<locals>.<listcomp>)rÜ   rÍ  )ZcadenaZpalabrasZpalabras_capitalizadasrq   rq   rr   Úcapitalizar_centro_idD  s    
r  c                 C   s    |   d¡}| ¡  d |¡}|S ri  )rÜ   rù  rÍ  )Zcentro_originalZdivisionZcentro_formateadorq   rq   rr   rµ  n  s    

rµ  c                 C   sÜ   t |ƒ}t ¡  d¡}|dkrf| t j}d|d d ddiddidœiddd	id
d
d
d
d
d
d
d
dœ	ig}nd|dkrÊ| t j}t |ƒ}d|dd|› �idd dœdd dœdœiddd	id
d
d
d
d
d
d
d
d
dœ
ig}t| |¡ƒ}|S )Nrá  rg   ú$matchr“  T)rÀ   r¢  r¸   r¢  r¸   ú$projectú	$toStringú$_idrŽ   )	rÐ   rã  rÀ   rä  rÚ   Úalertar¸   r¢  Ú
fin_estador™  ú$regexú^©r“  z$eq©rÀ   rã  r"  r¸   )
rÐ   rã  rÀ   rä  rÚ   r!  Zrangor¸   r¢  r"  )	r  r   r‡  rì  r„  r  rE  rÞ   Ú	aggregate©r’   r  rÀ   r  r—  r  Úpipelinerº  rq   rq   rr   Úobtener_alertas_activast  sf    
ûÿ
öÿö
üÿõÿór*  c                 C   s    t |ƒ}t ¡  d¡}|dkr*| t j}n|dkrD| t j}t |ƒ}d|dd|› �idd dœdd dœd	œid
ddiddddddddddœ
ig}t| |¡ƒ}|S )Nrá  rg   r™  r  r#  r$  Tr%  r&  r  r  r   rŽ   )
rÐ   rã  rÀ   rä  rÚ   r!  Úfallar¸   r¢  r"  )	r  r   r‡  rì  r„  r  rE  rÞ   r'  r(  rq   rq   rr   Úobtener_fallas_activasÀ  s<    
üÿ	õÿ÷r,  c                 C   s`   g }t | d|ƒD ]}| |d ¡ qtdd„ |D ƒƒ}tdd„ |D ƒƒ}|rPdS |rXdS dS d S )	Nrg   r!  c                 s   s   | ]}|d kV  qdS ©rÏ   Nrq   ©rÓ   r¸  rq   rq   rr   r    s     z estado_enviro.<locals>.<genexpr>c                 s   s   | ]}|d kV  qdS ©rÍ   Nrq   r.  rq   rq   rr   r    s     rÏ   rÍ   rÎ   )r*  rÃ   rª  )r’   rÀ   Úestado_enviroZactivaÚcriticoÚatencionrq   rq   rr   r0  ü  s    r0  c                 C   sD   | |g}t dd„ |D ƒƒ}t dd„ |D ƒƒ}|r4dS |r<dS dS d S )Nc                 s   s   | ]}|d kV  qdS r-  rq   r.  rq   rq   rr   r    s     z estado_centro.<locals>.<genexpr>c                 s   s   | ]}|d kV  qdS r/  rq   r.  rq   rq   rr   r    s     rÏ   rÍ   rÎ   )rª  )r0  Zestado_nanooxÚestado_centror1  r2  rq   rq   rr   r3    s    r3  c           	      C   sx   g }|dkr| t  j}n|dkr*| t j}t||dœd||dœidd�}| |¡ |rt| |¡ td|› d	|› �ƒ d S )
Nrg   r™  ©rÐ   rÀ   rQ  )r¢  r¸   Fr”  úAlerta ú revisada por usuario ©r„  r  rE  r'   rÃ   rˆ  rm   )	r’   r  rÀ   ÚidxÚusuario_revisionrã  r¸  r  rî  rq   rq   rr   Úactualizar_revision_alerta-  s(    
ýþÿô

r:  c           
   	   C   s¼   g }|dkr| t  j}n|dkr*| t j}| ||dœ¡}td|›�ƒ |sftd|› d|› d�ƒ d S t||dœd||d	œid
d�}	|	g}|r¸| |¡ td|› d|› d|› d|› �ƒ d S )Nrg   r™  r4  zfin_estado_falla=z$No se encontro el documento con _id=z y centro_id=z#; Probablemente ya fue consolidado.rQ  )r"  r¸   Fr”  zFalla z en centro r6  z el )r„  r  rE  r‘   rm   r'   rˆ  )
r’   r  rÀ   r8  r9  rã  r¸  r  Zfin_estado_fallarî  rq   rq   rr   Úactualizar_revision_fallaI  s2    
üþÿó
r;  c                 C   sx   g }|dkr| t  j}n|dkr*| t j}t||dœdd|iidd�}| |¡ |rt| |¡ td|› d	|› d
�ƒ d S )Nrg   r™  r4  rQ  r"  Fr”  r5  z" actualizada con fin estado a las z desde Localr7  )r’   r  rÀ   r8  rã  r¸  r  rî  rq   rq   rr   Úactualizar_fin_estado_alertap  s(    
ý ÿÿõ

r<  c                  C   s   t t ¡ ƒd } | S )Nr   )rÞ   Zenviro_metadata_collectionrÂ   )Zcarrq   rq   rr   Úobtener_centros_areas_regiones�  s    r=  c                 C   sT   g }|   ¡ D ]B\}}|  ¡ D ]0\}}|  ¡ D ]\}}d|kr,| |d ¡ q,qq|S )NrÐ   )rà   rÃ   )rf  Zidsrä   Zregion_valuesr  Zarea_valuesr  Zcentro_valuesrq   rq   rr   Úobtener_ids‘  s    r>  c                 C   s<   i }t | ƒD ]*}tt| ¡ ƒd t| ¡ ƒd ƒ||< q|S )Nra   rb   )r>  r3  Úobtener_estado_servicio_centrore  )rf  Únuevos_valoresr  rq   rq   rr   Ú obtener_valores_actuales_centros¨  s    (rA  c           	      C   sh   t tƒ}|  ¡ D ]J\}}| ¡ D ]8\}}|› d|› �}| ¡ D ]\}}d || |d < q>q qt|ƒ}|S )NrÛ   rÐ   )r   r  rà   )	rf  r—  rä   r  r  r/  r4  r  rs   rq   rq   rr   Úagrupar_por_region_area¶  s    rB  c                 C   s@   | }|}|  ¡ D ]*\}}|D ]}||kr|| || |< qq|S rv   rÑ  )Zagrupacion_por_region_areaZdict_estados_centror—  r@  r0  r/  rÀ   rq   rq   rr   Ú$agregar_estado_centros_a_consolidadoÇ  s    rC  c                 C   s    d| krdS d| krdS dS d S )NrÏ   rÍ   rÎ   rq   )rÚ   rq   rq   rr   Úactualizar_valorÕ  s
    rD  c                 C   sX   i }| }|  ¡ D ](\}}d dd„ | ¡ D ƒ¡}|||< q|D ]}t|| ƒ||< q>|S )Nr^  c                 s   s   | ]}|d k	r|ndV  qd S )NrÎ   rq   )rÓ   r`  rq   rq   rr   r  å  s     z0estado_resultante_area_region.<locals>.<genexpr>)rà   rÍ  rØ   rD  )Zconsolidado_estados_por_centroÚnuevo_diccionarior—  r0  r/  Zconcatenated_valuesrq   rq   rr   Úestado_resultante_area_regionÝ  s    
rF  c                 C   sb   | }t tƒ}| ¡ D ]&\}}| d¡\}}||  |7  < qt|ƒ}|D ]}t|| ƒ||< qH|S ri  )r   r  rà   rÜ   r  rD  )Zestados_resultante_area_regionrE  Zdiccionario_agrupador0  Zvalores_concatenadosrä   r  rq   rq   rr   Úestado_resultante_regionô  s    rG  c                 C   sl   i }|   ¡ D ]Z\}}i ||< |  ¡ D ]@\}}i || |< |D ]&}| d¡d }d|i|| | |< q<q$q|S )NrÛ   r   rÐ   )rà   rÜ   )rf  r?  rä   r  r  r/  r  Ú
centro_keyrq   rq   rr   Útransformar_diccionario&  s    rI  c                 C   s¶   i }t d| › �ƒ | dkrPt|ƒD ]*}tt| ¡ ƒd t| ¡ ƒd ƒ||< q"nb| dkr‚t|ƒD ]}tt| ¡ ƒd d ƒ||< q`n0| dkr²t|ƒD ]}td t| ¡ ƒd ƒ||< q’|S )Nz*ENTRANDO A ESTADO ACTUAL CENTRO EN PAGINA ÚHOMEra   rb   rg   r™  )rm   r>  r3  r?  re  )Úpagerf  r@  r  rq   rq   rr   Ú-obtener_valores_actuales_centros_por_servicioV  s    *rL  c                 C   s"  i }|dkrFt |ƒD ].}tt| | ¡ ƒd t| | ¡ ƒd ƒ||< qnØ|dkr²| t j}t |ƒD ]N}| d|iddi¡d d t| ||dƒ@ }|r`tt| | ¡ ƒd d ƒ||< q`nl|d	k�r| t j}t |ƒD ]N}| d|iddi¡d d t| ||dƒ@ }|rÎtd t| | ¡ ƒd ƒ||< qÎ|S )
NrJ  ra   rb   rg   rÀ   rÐ   r   r¢   r™  )r>  r3  r?  re  r�   rþ   r‘   Ústatus_servicio_permiso_usuario)r’   rK  rf  rŒ   r@  r  rÄ   Zstatus_servicio_centrorq   rq   rr   Ú/obtener_valores_actuales_centros_por_servicio_2m  s"    .
* 

*rN  c                 C   s‚   t | tƒr^g }|  ¡ D ],\}}t|ƒ}|d kr:| |¡ q|| |< q|D ]
}| |= qH| s~d S n t | tƒr~dd„ | D ƒ} | s~d S | S )Nc                 S   s    g | ]}t |ƒd k	rt |ƒ‘qS rv   )Ú
clean_none©rÓ   r±  rq   rq   rr   rÕ   ›  s      zclean_none.<locals>.<listcomp>)r  r  rà   rO  rÃ   rÞ   )rf  Zkeys_to_deleter4  r`  Zcleaned_valuerq   rq   rr   rO  †  s     


rO  c                 C   s    | t  j}dd|iiddddiiiddidddd	id
œiddiddddidœiddiddddidœiddid||dœiddddœig}t| |¡ƒ}|d d S )Nr  rŒ   r  rµ   ú$objectToArrayú	$permisosz$unwindz$permisos.kz$permisos.v)rä   Zciudadesz	$ciudadesz$ciudades.kz$ciudades.v)Zciudadr/  z$centrosz
$centros.kz
$centros.v)rÀ   r  z
$servicios)rÀ   zservicios.kr   z$servicios.v.status)rÐ   r¢   r¢   )r�   rf   rÞ   r'  )r’   rŒ   rÀ   ro  r“   r)  r—  rq   rq   rr   rM  ¡  sR    

 ÿÿ ÿþ ÿþ ÿþþþß&rM  c           	      C   s`   t dƒ tt| ƒ}t|ƒ}t d|› �ƒ t||ƒ}tt|ƒ|ƒ}t|ƒ}t|ƒ}|||dœ}|S )Nz#ENTRANDO A CONSOLIDADOS ACTUALIZADOzdata: ©r/  r  rk  )	rm   r¹   r“   rI  rL  rC  rB  rF  rG  )	rŒ   rK  Úpermisos_usuariorf  r@  Úestados_centrosÚestados_areasÚestados_regionesÚconsolidado_estadosrq   rq   rr   Ú1consolidado_empresa_por_usuario_activo_y_servicioÌ  s    

rY  c                 C   s˜   t dƒ | t j}|dkr&t||ƒ}nt| t| d|i¡ƒd ƒ}t|ƒ}t| |||ƒ}t	t
t|ƒ|ƒƒ}t d|›�ƒ t|ƒ}t|ƒ}	|||	dœ}
|
S )NzENTRANDO A CONSOLIDADOSrJ  rŒ   r   zestados_centros=rS  )rm   r�   rf   r¹   Úprocesar_permisosrÞ   rÂ   rI  rN  rO  rC  rB  rF  rG  )r’   rŒ   rK  r“   rT  rf  r@  rU  rV  rW  rX  rq   rq   rr   Ú3consolidado_empresa_por_usuario_activo_y_servicio_2æ  s    
r[  c           
      C   sj   d}t  | |¡}t  ||¡}|| }|j|j }}|d }|d d }	|d }|› d|› d|	› d|› d�S )Nz%Y-%m-%d-%H:%M:%Si  é<   zd-zh-zm-r`  )r   rõ  r„   Úseconds)
Zfecha_inicio_strZfecha_fin_strZformatoZfecha_inicioÚ	fecha_finZ
diferenciaZdiasZsegundosZhorasZminutosrq   rq   rr   Úobtener_diferencia  s    r_  c                 C   s8   | t  j}| d|i¡}|r4||kr4||  dd¡S dS )NrÀ   r¢   F)r�   rþ   r‘   r�   )r’   rÀ   ro  rÄ   rø  rq   rq   rr   Úobtener_status_servicio  s
    
r`  c                 C   s.   | t  j}| d|iddi¡}|r&|S dS dS )z_
    Retorna el estado B, A o C de un centro en especifico desde la coleccion user.estados
    rÀ   rÐ   r   rÎ   N)r�   r†  r‘   )r’   rÀ   rŽ  Zestado_serviciosrq   rq   rr   Ú'ORIGINAL_obtener_estado_servicio_centro   s
    
ra  rÑ   c                 C   s<   z | t  j}| d|iddi¡W S  tk
r6   Y dS X dS )z7 Helper para evitar N+1 queries. Trae el doc completo. rÀ   rÐ   r   N)r�   r†  r‘   r¬   )r’   rÀ   Úcollrq   rq   rr   r?  .  s
    
r?  c                 C   sx   zt | d|ƒ}dd„ |D ƒ}W n   g }Y nX | dd¡}zt| |dƒ}W n   d}Y nX || d¡| d¡|d	œS )
Nrg   c                 S   s   g | ]}|d  ‘qS ©r!  rq   ©rÓ   ræ  rq   rq   rr   rÕ   m  s     z+estado_enviro_servicios.<locals>.<listcomp>ra   rÎ   TrÏ   rÍ   ©r¢   Zconteo_cZconteo_aÚstatus_service©r*  r�   r`  Úcount©r’   rÀ   Ú
estado_docr  rÙ   Zestado_operativoÚ
status_srvrq   rq   rr   Úestado_enviro_serviciosi  s    

ürl  c                 C   sx   zt | d|ƒ}dd„ |D ƒ}W n   g }Y nX | dd¡}zt| |dƒ}W n   d}Y nX || d¡| d¡|d	œS )
Nr™  c                 S   s   g | ]}|d  ‘qS rc  rq   rd  rq   rq   rr   rÕ   ‚  s     z+estado_nanoox_servicios.<locals>.<listcomp>rb   rÎ   TrÏ   rÍ   re  rg  ri  rq   rq   rr   Úestado_nanoox_servicios  s    

ürm  c                 C   s0   zt | |dƒ}W n   d}Y nX ddd|dœS )Nrd   TrÎ   r   re  ©r`  ©r’   rÀ   rj  rk  rq   rq   rr   Úestado_pss_servicios”  s
    
rp  c                 C   s0   zt | |dƒ}W n   d}Y nX ddd|dœS )Nrc   TrÎ   r   re  rn  ro  rq   rq   rr   Úestado_scapp_servicios›  s
    
rq  c                 C   s¦   |  ¡  d¡}t|ƒdkr"|d nd}t|ƒdkr:|d n|d }|dkpP|d	k}| di ¡}| d
¡}t|tƒrx|}	n|dkr†d}	n|r�d}	nd}	d}
|	dd|
dœS )z
    Manejador para Flux.
    rÛ   rÙ  r›  r^  rï   rœ  r   re   ©ZboatZboatsZbarcosr¢   TrÎ   re  )re  rÜ   rû   r�   r  r  )r’   rÀ   rj  r³  rä   r  Úes_zona_fluxZinfo_dbÚ	status_dbÚestado_finalÚstatus_service_permisorq   rq   rr   Úoriginal_estado_flux_servicios¢  s&    

ürw  c                 C   sØ   |  ¡  d¡}t|ƒdkr"|d nd}t|ƒdkr<|d }n|d }|dkpR|d	k}| d¡}d
}t|tƒrx| d¡}nt|tƒrˆ|}nt|tƒr–|}d}	t|tƒrª|}	n|dkr¸d}	n|rÂd}	nd}	d}
|	dd|
dœS )uÓ   
    Manejador para Flux (VersiÃ³n Robusta / Anti-Crash).
    Soporta inconsistencias de DB: 
    - flux: {'status': 'B'} (Dict)
    - flux: 'B' (String)
    - flux: true (Bool)
    - flux: None (No existe)
    rÛ   rÙ  r›  r^  rï   rœ  r   re   rr  Nr¢   rÎ   Tre  )re  rÜ   rû   r�   r  r  r  r=  )r’   rÀ   rj  r³  rä   r  rs  Zraw_fluxrt  ru  rv  rq   rq   rr   Úestado_flux_serviciosÉ  s8    






ürx  c                 C   s(   ddd| ddgiid| dd| igigiS )Nú$concatz$toUpperz	$substrCPr   rŽ   z	$strLenCPrq   )Zfieldrq   rq   rr   Úcapitalize_first_letter  s
    þÿrz  c                 C   sÞ   | t  j}dd|iidddiidddd	d
idtdƒddd	didtdƒddd	didtddddgidgiƒddtddddgidgiƒdtdƒdtdƒgiidœdœiidœdœiidœdœiiig}t| |¡ƒ}|rÚ|d S i S )Nr  rŒ   r  rµ   rŽ   z$replaceWithz$arrayToObjectz$maprQ  rR  rä   z
$$region.kz
$$region.vr  z$$area.kz$$area.vr  z$arrayElemAtz$splitz
$$centro.krÛ   r   rÐ   ry  )rP  r  )ÚinputÚasÚin)r�   rf   rz  rÞ   r'  )r’   rŒ   r§  r)  r?  rq   rq   rr   Ú#obtener_servicios_por_region_y_area!  sl    

 ÿ
 ÿÿ
 ÿÿ÷ÿúýÿþýÿþýÿû4r~  c           	   	   C   sx   t |ƒ}i }|D ]b}| ¡ }t| |ƒ}|r.|ni }t| ||ƒt| ||ƒt| ||ƒt| ||ƒt| ||ƒdœ}|||< q|S )u«   
    Recorre todos los centros, obtiene su documento de estado una Ãºnica vez (cache)
    y construye el diccionario de servicios (Enviro, Nanoox, Pss, Scapp y Flux).
    r‘  )r>  re  r?  rl  rm  rq  rp  rx  )	r’   Zdata_permisosZ
id_centrosZdict_centrosrÀ   rH  rj  Z
doc_seguroZservicios_centrorq   rq   rr   Úestados_servicios_region_area_2w  s    





ú
r  c              
   C   sf   ddt |ƒidddiidddiidddiiddd idd idd igigi}t|  |¡ƒ}|r^d	S dS d S )
Nz$andrÐ   r¢  r“  Tr¸   r"  rË   F)r,   rÞ   rÂ   )Úcol_enviro_alertasr8  rÅ   rº  rq   rq   rr   Úcheck_alerta_incompletaÓ  s"    



ýÿûÿr�  c                 C   sj  |dkr| t  j}n|dkr&| t j}| d|i¡}|�rX|d  d¡dd… }d |¡}||d d	œ}d
||d i dœi}|j||dd� dd|d › �|d |d |d |d |d |d t|d |d ƒdœii}	| ||	¡}
td|› �ƒ |
j	dk�r&|
j
dk�rtdƒ d}ntdƒ d}ntdƒ d}|�rf| d|i¡ td|› d�ƒ ntd|› �ƒ d S )Nrg   r™  rÐ   rã  rÛ   r   rï   rÀ   ©rã  rÀ   ú$setOnInsert©rã  rÀ   rð  Tr”  r  ú
variables.rä  rÚ   r!  r¸   r¢  r"  ©ZiniciorÚ   r!  r¸   r¢  r"  Zduracionz/ Consolidado de Alertas actualizado con alerta ú(El documento se actualizo correctamente.ú:El documento coincidio con el filtro, pero no se modifico.Fú>No se encontro ningun documento que coincidiera con el filtro.z
La alerta z4 se ha agregado al consolidado y removido de alertasz& No se encontro alerta asociada al id )r„  r  rE  r‘   rÜ   rÍ  rS  r_  rm   rÞ  r•  rJ  )r’   r  r8  r  rM  Ú	fecha_strrã  rL  ÚactualizacionÚactualizacion_variabler?  rq   rq   rr   Ú(actualizar_consolidado_alertas_revisadas,  sX    

þýÿ	ùÿÿr�  c                 C   sx  |dkr| t  j}n|dkr&| t j}d|i}| |¡}|�rf|d  d¡dd… }d |¡}||d d	œ}d
||d i dœi}	|j||	dd� dd|d › �|d |d |d |d |d |d t|d |d ƒdœii}
| ||
¡}td|› d�ƒ |j	dk�r,|j
dk�rtdƒ d}	ntdƒ d}	ntdƒ d}	|	�rt|d }| d|i¡ td|› d�ƒ ntd|› �ƒ d S ) Nrg   r™  rÐ   rã  rÛ   r   rï   rÀ   r‚  rƒ  r„  Tr”  r  r…  rä  rÚ   r!  r¸   r¢  r"  r†  z. Consolidado de Fallas actualizado con alerta rù   r‡  rˆ  Fr‰  z	La falla z3 se ha agregado al consolidado y removido de fallasz* No se encontro falla asociada a la falla )r„  r  rE  r‘   rÜ   rÍ  rS  r_  rm   rÞ  r•  rJ  )r’   r  r8  r  rÅ   rM  rŠ  rã  rL  r‹  rŒ  r?  rq   rq   rr   Ú'actualizar_consolidado_fallas_revisadasq  s\    


þýÿ	ùÿÿrŽ  rŽ   rï   c                    sˆ   t | tƒrbi }|  ¡ D ]F\}}ˆ ˆkrD|d d…  ¡ |dd …  }n|}t|ˆ d ˆƒ||< q|S t | tƒr€‡ ‡fdd„| D ƒS | S d S )NrŽ   c                    s   g | ]}t |ˆ ˆƒ‘qS rq   )Úcapitalize_first_keysrP  ©ÚdepthÚ	max_depthrq   rr   rÕ   Æ  s     z)capitalize_first_keys.<locals>.<listcomp>)r  r  rà   rž  r�  rÞ   )rZ  r‘  r’  Únew_dictr4  r`  Znew_keyrq   r�  rr   r�  º  s    

r�  c              	   C   sÈ  | t  j}i }|d D �]ª}i ||< |d | D �]Ž}i || |< |d | | D �]j}t| d| ¡ i¡ƒ}|�r®i || | |< |d | | | D �]}|d | | | | d }	|dkrô|d d d }
|	oØ|
}d|i|| | | |< q˜|dk�r2|d d d }
|	�o|
}d|i|| | | |< q˜|dk�rp|d d d }
|	�oT|
}d|i|| | | |< q˜|dkr˜|d d d }
|	�o�|
}d|i|| | | |< q˜qRg || | |< qRq0q|S )	u  
    REaliza el cruce entre los permisos que posee el usuario con los permisos actuales almacenados en la coleccion ciclos,
    y construye un nuevo diccionario con el â€œpermiso efectivoâ€� (status) para cada servicio de cada centro, segun {REGION{AREA{CENTRO}}
    rµ   rÀ   r¢   ra   r   rb   rc   rd   )r�   rþ   rÞ   rÂ   re  )r’   Úpermisos_usuariosrÄ   Úresult_dicträ   r  r  Úinfo_centro_cicloro  r¢   Zstatus_centro_ciclosZcomparacion_enviroZcomparacion_nanooxZcomparacion_scappZcomparacion_pssrq   rq   rr   Úoriginal_procesar_permisosË  s<    





r—  c              	   C   sD  | t  j}i }|d D �]&}i ||< |d | D �]
}i || |< |d | | D ]è}t| d| ¡ i¡ƒ}|�r*|d }i || | |< |d | | | D ]ˆ}	|	|k�rt||	 tƒ�r|d | | | |	  dd¡}
||	  dd¡}|
oò|}d|i|| | | |	< qžddi|| | | |	< qžqRi || | |< qRq0q|S )u  
    Realiza el cruce entre los permisos que posee el usuario con los permisos actuales almacenados en la coleccion ciclos,
    y construye un nuevo diccionario con el â€œpermiso efectivoâ€� (status) para cada servicio de cada centro, segun {REGION{AREA{CENTRO}}
    rµ   rÀ   r   r¢   F)r�   rþ   rÞ   rÂ   re  r  r  r�   )r’   r”  rÄ   r•  rä   r  r  r–  Zdatos_cicloro  Zstatus_usuarioZstatus_cicloZcomparacionrq   rq   rr   rZ  ö  s(    
 rZ  c                 C   sN   | t  j}t| d|i¡ƒ}|rF|d }t|d ƒ|d< t| |ƒ}|S d S d S )NrŒ   r   rµ   )r�   rf   rÞ   rÂ   r�  rZ  )r’   r¸   r“   r•   Úusuario_capitalizador  rq   rq   rr   Ú%original_procesar_permisos_de_usuario  s    

r™  c              
   C   s˜   zZ| t  j}t| d|i¡ƒ}|rR|d }t|d ƒ|d< t| |ƒ}t|ƒ}|W S W d S W n8 tk
r’ } ztd|› �ƒ i  W Y ¢S d }~X Y nX d S )NrŒ   r   rµ   z#Error procesando permisos usuario: )	r�   rf   rÞ   rÂ   r�  rZ  Únormalizar_schema_legacyr¬   rm   )r’   r¸   r“   r•   r˜  r  Zpermisos_finalesr­   rq   rq   rr   Úprocesar_permisos_de_usuario.  s    


r›  c              
   C   s  t  | ¡}zÎ| ¡ D ]À\}}t|tƒs(q| ¡ D ]¢\}}t|tƒsDq0| ¡ D ]„\}}t|tƒrLd|ksr|d dkrL| ¡  d¡}t|ƒdkr”|d nd}	t|ƒdkr¬|d n|d	 }
|	dkpÂ|
d
k}d|i|d< qLq0qW n: tk
�r } zt	d|› �ƒ |  W Y ¢S d}~X Y nX |S )u¿   
    Normaliza permisos legacy.
    CORRECCIÃ“N: Si falta el permiso 'flux', verifica si el centro es zona Flux/Barcos.
    Si es asÃ­, otorga el permiso (status: True) automÃ¡ticamente.
    re   NrÛ   rÙ  r›  r^  rï   rœ  r   rr  r¢   z!Advertencia normalizando legacy: )
r  rf  rà   r  r  re  rÜ   rû   r¬   rm   )rT  Zpermisos_normalizadosZ
region_keyr  Zarea_keyr/  rH  r  r³  Ú	region_idÚarea_idrs  r­   rq   rq   rr   rš  H  s(    

 
 
rš  c                 C   s´   i }|   ¡ D ]¢\}}|  ¡ D ]�\}}|  ¡ D ]~\}}|  ¡ D ]l\}	}
||
kr<||kr\i ||< t |¡|| |< || |   ¡ D ](\}}||
| kr~|
| | d |d< q~q<q,qq|S )Nr¢   rf  )rà   r  rf  )Úoriginal_dict1Údict2r“  Zkey1Zsubdict1Zkey2Zsubdict2Z
key_regionÚregion_dataZkey_areaÚ	area_datar  rØ   rq   rq   rr   ÚORIGINAL_update_status_serviceo  s    r¢  c                 C   s   t | ƒ ¡  ¡ S )uì   
    Genera una llave exclusiva para comparar permisos.

    `casefold` permite comparar mayÃºsculas/minÃºsculas sin modificar el nombre que
    finalmente se envÃ­a al frontend. El `strip` evita rechazos por espacios accidentales.
    )r  r_  Úcasefold)r`  rq   rq   rr   Ú_permission_lookup_key‚  s    r¤  c              
   C   sÄ  |si S �zzi }|  ¡ D ]f}t|tƒs(q|  ¡ D ]L}t|tƒs@q0| ¡ D ]2\}}t|ƒ}|rd||krrtd|› �ƒ‚|||< qHq0qi }|  ¡ D ]ò\}	}
|
 ¡ D ]à\}}| t|ƒ¡}t|tƒs¾qœt|tƒsÊqœi }| ¡ D ]4\}}t|ƒ}|rô||k�rtd|› �ƒ‚|||< qÖt |¡| 	|	i ¡|< ||	 |  ¡ D ]H\}}| t|ƒddi¡}t|tƒ�rh| dd¡}nt
|ƒ}||d< �q2qœqŒ|W S  tk
�r¾ } ztd|› �ƒ i  W Y ¢S d}~X Y nX dS )u  
    Cruza los estados calculados (`original_dict1`) con los permisos del usuario (`dict2`).

    Los identificadores de centro y servicio se comparan sin distinguir mayÃºsculas. Las
    llaves originales se conservan en la respuesta para no cambiar el contrato con el FE.
    zPermiso de centro ambiguo: zPermiso de servicio ambiguo: r¢   Frf  u)   Error crÃ­tico en update_status_service: N)rØ   r  r  rà   r¤  r(  r�   r  rf  rá   r=  r¬   rm   )rž  rŸ  Zpermissions_by_centerr   r¡  Úcenter_nameZcenter_permissionsZ
center_keyr—  r0  ÚcentersZcenter_statesZpermissions_by_serviceÚservice_nameZservice_permissionÚservice_keyZservice_stateZpermission_statusr­   rq   rq   rr   Úupdate_status_serviceŒ  sZ    

ÿ


 ÿr©  c              
   C   s†   t ||dœd|idd�g}z(| j|dd�}|jdkr:d}nd}|W S  tk
r€ } z td|j› �ƒ d}| W Y ¢S d }~X Y nX d S )	N©rÀ   rä  rQ  Tr”  Fr¦  r   zError de escritura en bulk: )r'   rˆ  r•  r+   rm   rÎ  )r§  rÀ   rä  r@  rŠ  r?  r(  r  rq   rq   rr   Úactualizar_umbralð  s     ýÿ
r«  c              
   C   sB  g }t d|›�ƒ t dt›�ƒ |dkr4| t j}n|dkrF| t j}t d|› �ƒ |D ]d}t d|›�ƒ t d|d ›�ƒ t d	|d
 ›�ƒ |d |d
 dœ}d|i}| t||dd�¡ qXz| |¡}t dƒ W nh tjk
�r
 }	 zt d|	j	› �ƒ W 5 d }	~	X Y n4 tj
k
�r< }
 zt d|
› �ƒ W 5 d }
~
X Y nX d S )Nzservice=zNANOOX_DATABASE_NAME=rg   r™  zumbrales_desde_local: zumbral=zumbral["centro_id"]=rÀ   zumbral["variable"]=rä  rª  rQ  Tr”  r	  z.Error en la operacion de escritura en bloque: zError en PyMongo: )rm   rE  r„  rë  rÃ   r'   rˆ  r)   r+   rÎ  r  )r’   r  rë  Z
operationsr  ZumbralÚfilterr  r—  r  r­   rq   rq   rr   Úguardar_umbrales_activos%  s,    

 r­  rë  c              
   C   s^  |�r`d}�z|  d¡}|  d¡}|r0t|tƒsDtd|› �ƒ W dS | t }|| ¡ kr~|j|dddd	œd
� td|› d�ƒ || }t ¡ }|j	d|idgd�}	|	râ|	  d¡|	  d¡dœ}
t|
|ƒ |
|krât|› d�ƒ W dS d|i|d|i–}| 
|¡ td|› d|› �ƒ W nH tk
�r\ } z(tddtƒ k�r<|nd› d|› �ƒ W 5 d}~X Y nX núd}|  d¡}|  d¡}t ¡  d¡}| t j}| 	d|i¡}	td|›d|›�ƒ |	�r6|	  d¡d dd… |dd… k�r&| |¡ td|	d id d|iiƒ}| |g¡}td!|j› d"|j› �ƒ nt|› d#�ƒ n$| |¡ | 
||gd$œ¡ td%ƒ dS )&u~   
    Guarda los umbrales en una colecciÃ³n de series de tiempo.
    Si la colecciÃ³n no existe, la crea como time series.
    Úumbrales_v2r  rf  u   Datos de umbrales invÃ¡lidos: Nr  rÀ   r]  )Z	timeFieldZ	metaFieldÚgranularity)Z
timeseriesu   ColecciÃ³n z creada como time series©r  r›  rY  Úsetpoin_offÚ
setpoin_on©r±  r²  z6: Umbrales sin cambios, no se inserta nuevo documento.zNuevo umbral insertado en z para centro z$Error al guardar umbrales en centro r¨  rø   rë  r7  z Guardar umbrales Nanoox: centro=z nuevos_datos=rÒ  r›  é   rÐ   r  z*Upsert realizado. Documentos modificados: z, documentos insertados: z7: Datos de Umbrales sin cambios, no se actualiza en bd.©rÀ   rÒ  zNuevo documento insertado.)r�   r  r  rm   rE  Zlist_collection_namesZcreate_collectionr   Zutcnowr‘   r  r¬   Úlocalsr‡  rì  rë  rÃ   r'   rˆ  r•  r–  )r’   rë  r>  r:  rÀ   Znuevos_datosr=  Zumbrales_colZfecha_actualÚexisting_docZultimo_datorÔ   r­   r  rã  Zcol_nanoox_umbralesZupdate_operationr—  rq   rq   rr   Úguardar_umbrales_nanooxH  s~    

ýþþþ
 ÿ ý
8


$


þ
r¸  c           	   
   C   sÖ   zŽ|rVd}| | }|j d|idgd�}td|›�ƒ |rŒ| d¡| d¡dœ}|W S n6| j}|  d|i¡}d }|r†|d	 d
 d d… }|W S W nB tk
rÐ } z$td|› d|› d|jj› �ƒ ‚ W 5 d }~X Y nX d S )Nr®  rÀ   r°  rY  zexisting_doc=r±  r²  r³  rÒ  r›  r´  z0Error al obtener datos de generador para centro r©   rù   )r‘   rm   r�   rë  r¬   r	  r
  )	Z	db_nanooxrÀ   r>  r:  r§  r·  Zumbrales_datary  r­   rq   rq   rr   rJ  ³  s.    þþ
rJ  c              
   C   sô   z¤| j }td|›�ƒ | d|i¡}td|›�ƒ |sPtdd|› d�iƒdfW S | d¡}t|tƒrpt|ƒd	krŠtdd
|› d�iƒdfW S |d }td|›�ƒ |W S  tk
rî } z,td|› d|› �ƒ tddiƒdf W Y ¢S d}~X Y nX dS )aY  
    Obtiene el ultimo set de umbrales para un centro desde la coleccion 'umbrales'
    en la base de datos scapp. Cada documento tiene la forma:
      {
        "centro_id": "...",
        "datos": [
          {
            "SFR":     {"A": int,   "C": int},
            "AYUNO":   {"A": float, "C": float},
            "ALARMAS": {"A": int,   "C": int},
            "fecha":   "YYYY-MM-DD HH:MM:SS"
          },
          ...
        ]
      }
    Devuelve JSON con el ultimo entry (incluye SFR, AYUNO, ALARMAS y fecha).
    En caso de error o ausente, devuelve jsonify con el codigo apropiado.
    rÜ  rÀ   zdoc=ru   z+No se encontraron umbrales para centro_id "ú"rB  rÒ  r   z>Documento de umbrales mal formado o sin datos para centro_id "r›  zultimo=z>[get_umbrales_scapp] Error al obtener umbrales para centro_id=rø   z!Error interno al obtener umbralesrú   N)	rë  rm   r‘   r   r�   r  rÞ   rû   r¬   )Zdb_scapprÀ   r§  rÔ   rÒ  Zultimor­   rq   rq   rr   Úget_umbrales_scappÝ  s>     
ÿþ
 
ÿþ ÿþrº  c              
      sø  t dƒ | d¡}| d¡}|dks,|dkr<tddiƒdfS dd	d
h‰ t|tƒr\t|ƒˆ krrtddˆ › �iƒdfS dD ]z}| |¡}t|tƒrœddh |¡s¸tdd|› d�iƒdf  S t|d tƒrÔt|d tƒsvtdd|› d�iƒdf  S qv| d	¡}t|tƒ�rddh |¡�s(tddiƒdfS z,t|d ƒ|d	 d< t|d ƒ|d	 d< W n* t	t
fk
�r~   tddiƒdf Y S X t ¡  d¡}|d|i–}	| t j}
| t }|j}t dƒ zè|
 d|i¡}|�rht dƒ | d¡�rô| dg ¡d ni }‡ fdd„| ¡ D ƒ}||k�rXtd|d idd|	iiƒ}|
 |g¡}t d |j› d!|j› �ƒ nt |› d"�ƒ n8t d#ƒ |
 ||	gd$œ¡ t d%|› d&�ƒ t|||d'ƒ W nP tk
�rò } z0t d(|jj› d)|› �ƒ tdd*iƒd+f W Y ¢S d}~X Y nX dS ),aÂ  
    Guarda o actualiza en la coleccion 'umbrales' un documento con:
      - centro_id
      - datos: lista de entradas donde cada entrada tiene directamente las llaves
        "SFR", "AYUNO", "ALARMAS" y "fecha"
    Ejemplo de entrada JSON esperada (payload):
    {
      "centro": "centro_001",
      "datos": {
        "SFR":     {"A": 50, "C": 80},
        "AYUNO":   {"A": 0.5, "C": 2.0},
        "ALARMAS": {"A": 10, "C": 30}
      }
    }
    z#ENTRANDOA GUARDAR UMBRALES SCAPP!!!r  rf  Nru   z.Se requieren los parametros 'centro' y 'datos'rB  ÚSFRZAYUNOÚALARMASz$'datos' debe ser un dict con llaves )r»  r¼  rÍ   rÏ   ú'z'' debe ser un dict con llaves 'A' y 'C'zLos valores de 'z' deben ser enterosz-'AYUNO' debe ser un dict con llaves 'A' y 'C'z2Los valores de 'AYUNO' deben ser numericos (float)r7  rã  zConectados a la DBrÀ   zEntramos a existing umbralesrÒ  r›  c                    s   i | ]\}}|ˆ kr||“qS rq   rq   ©rÓ   rP  r  ©Zexpected_keysrq   rr   r6  R  s       z*guardar_umbrales_scapp.<locals>.<dictcomp>rÐ   r  zActualizado: modified=z, upserted=z+: sin cambios en umbrales, no se actualiza.zEntramos a nuevos umbralesrµ  z6Nuevo documento de umbrales Scapp insertado en centro r   Zadd_scapp_thresholdz2Error guardando umbrales Scapp por error en linea r€  z*El Serrvidor encontro un error inesperado'rú   )rm   r�   r   r  r  rß   ÚissubsetrÈ  rÝ  rI  r(  r   r‡  rì  ÚSCAPP_DATABASE_NAMErë  r�   r…  r‘   rà   r'   rˆ  r•  r–  r  r1   r¬   r	  r
  )r’   rŒ   rë  r  Znuevosr4  rŠ   Zayunorã  ZentradaÚcolr‹  r�  ZexistingZlastZlast_threshr  rÆ   r­   rq   r¿  rr   Úguardar_umbrales_scapp  sp    




 þ
 


þþ&rÃ  c                 C   s&  |dkr| t  j}n|dkr&| t j}t| d|iddi¡ƒ}g }|D ]Ú}|d }|d }|d }	|	d	krª|d
 }
|d }| |||	|
d k	r�|
nd |d k	rž|nd dœ¡ qF|	dkrF|d }|d }|d
 }|d }| |||	|d k	rè|nd |d k	rö|nd |d k	�r|nd |d k	�r|nd dœ¡ qF|S )Nrg   r™  rÀ   rÐ   r   rä  r¢   rå  râ  rè  rZ  )re  r¢   rå  r2  ÚcriticaZ	compuestaræ  rç  )re  r¢   rå  ÚatencionInfÚ
criticaInfÚatencionSupÚ
criticaSup)r„  rë  rE  rÞ   rÂ   rÃ   )r’   r  rÀ   r  Zumrë  rø  re  r¢   rå  r2  rÄ  rÅ  rÆ  rÇ  rÈ  rq   rq   rr   Ú enviar_umbrales_formateados_a_fel  sF    
û
ù

rÉ  c                 C   sX   g }| t  j}td|id|idd�}| |¡ |rP| |¡ td|› d�ƒ dS dS d S )NrÀ   rQ  Tr”  z
Estado de ú actualizado en ITGSMF)r�   r  r'   rÃ   rˆ  rm   )r’   rÀ   ré   r¸  rŽ  rî  rq   rq   rr   Úactualizar_estado_servicio—  s    
 ÿú	

rË  c                 C   sX   | t  j}g }td|id|idd�}| |¡ |rP| |¡ td|› d�ƒ dS dS d S )NrÀ   rQ  Tr”  zEstado variables de rÊ  F)r„  rð  r'   rÃ   rˆ  rm   )r’   rÀ   ré   Úcol_enviro_variablesr¸  rî  rq   rq   rr   Úactualizar_estado_variables¬  s    
 ÿú	

rÍ  z@/<service_name>/notifications_to_emails/<region>/<area>/<centro>c              
   C   sˆ  zð|   ¡  ¡ }|tkr2tdd| › d�dœƒdfW S t| }tƒ }|| t }t d¡}| |¡rt| |¡rt| |¡sˆtdddœƒdfW S t	||||ƒ}	|	sºtd	d
|  
¡ › d�dœƒdfW S td| | ¡ › d| ¡ › d| ¡ › �|	dœdœƒdfW S  tk
�r8 }
 z(td|
› �ƒ tdddœƒdf W Y ¢S d}
~
X Y nL tk
�r‚ } z,td|› �ƒ tdt|ƒdœƒdf W Y ¢S d}~X Y nX dS )z™
    Ruta API para obtener lista de correos por servicio y centro.
    Ejemplo limpio: GET /flux/notifications_to_emails/Loslagos/Puertomontt/Centro
    zInvalid ServicezEl servicio 'u   ' no es vÃ¡lido.)ru   r
  rë   u   ^[a-zA-Z0-9\sÃ±Ã‘-]+$zBad Requestu   Caracteres invÃ¡lidos en URLru   z No hay emails configurados para u    en esa ubicaciÃ³n)r¢   r
  rB  ZsuccessrÛ   )Z	target_idrh   )r¢   r  rf  rH  z%Error DB en notifications_to_emails: zInternal ErrorzError leyendo base de datosrú   Nr¹  zUnexpected Error)re  r_  r0   r   r/   r  r°   ÚcompilerF  r;   rž  Útitlerò  rm   r¬   r  )r§  rä   r  r  r¨  r  r’   r§  Úpatternrh   Zre_errr­   rq   rq   rr   Úget_emergency_emailsÄ  sL    
þý
þýþýù	&rÑ  z/<SERVICE>/post_alertasc              
   C   s¶   | }t j}tƒ }zL|g kr@t|||ƒ tdd| › d�iƒdfW S tdƒ tddiƒdfW S W nT tk
r° } z6td| › d|jj› d	|› �ƒ tdd
iƒdf W Y ¢S d }~X Y nX d S )Nré   z)Se han enviado correctamente las alertas rù   rH  z#No se han recibido datos de alertasrô   zError Enviando las alertas z: por error en linea r€  z5 No se han enviado correctamente las alertas a ITGSM )	r   r  r/   r  r   rm   r¬   r	  r
  )r#  r  r  r’   r­   rq   rq   rr   Úpost_alertasû  s    rÒ  z3/<SERVICE>/alertas_activas/<CENTRO>/<AREA>/<REGION>c              
   C   sÂ   t ƒ }| ¡ }| ¡ }| ¡ }|› d|› d|› �}td| › �ƒ z(t|| |ƒ}td| › �ƒ t|ƒdfW S  tk
r¼ } z6td| › d|jj› d|› �ƒ tdd	iƒd
f W Y ¢S d }~X Y nX d S )NrÛ   zSERVICE_ALERTA_ACTIVA: z/Se han enviado correctamente las alertas al FE rH  zERROR Enviando las alertas rÞ  r€  ré   z3 No se han enviado correctamente las alertas al FE rô   )r/   r   rm   r*  r   r¬   r	  r
  )r#  rd  rc  rb  r’   rÀ   Zalertas_activasr­   rq   rq   rr   Úalertas_to_fe  s    rÓ  z/<SERVICE>/revision_alertac           	   	   C   s  t ƒ }tj}td|› d�ƒ |rü|d }|d }|rêg g dœ}|D ]p}|d }|d }z0t|| ||d|ƒ t|| |ƒ |d	  |¡ W qB tk
r°   td
ƒ |d  |¡ Y qBX qB|rØtd|›�ƒ td|dœƒdfS tddiƒdfS ntddiƒdfS ntddiƒdfS d S )Nzdatos_alerta_revisada: r½  rf  r  ©Úno_revisadosÚ	revisadosrÐ   r"  ÚlocalrÖ  ú/No se ha podido revisar la alerta con _id {idx}rÕ  zalertas ids_dict=úLas alertas revisadas en SM son©ré   rf  rH  ré   ú-No se han podido revisar las alertas enviadasrô   ú(Se enviaron revisiones de alertas vaciasr�  úNo se han enviado datos)	r/   r   r  rm   r:  r�  rÃ   r¬   r   )	r#  r’   Zdatos_alerta_revisadaZdata_alertas_revisadasrÀ   Úids_dictr+  r8  r^  rq   rq   rr   Úrevisar_alerta_ITGSM!  s:    
þýrß  z//<SERVICE>/fin_estado_alerta_activa/<CENTRO_ID>c              
   C   sô   t dtj› d�ƒ tj}tƒ }|t j}t d|›d�ƒ |rð|d }|d }zNt|| |||ƒ t||ƒrztddiƒdfW S t	|| |ƒ tdd	iƒdfW S W nT t
k
rî } z6t d
| › d|jj› d|› �ƒ tddiƒdf W Y ¢S d }~X Y nX d S )Nzdatos_desde_LOCAL: r½  zdatos_alerta_no_revisada=r8  r"  ré   z\Se ha enviado correctamente el fin estado alerta pero no cunple para actualizar consolidado rH  zLSe han enviado correctamente el fin estado alerta e ingresado al consolidadozError enviando las alertas rÞ  r€  z5 No se ha enviado correctamente el fin estado alerta rô   )rm   r   r  r/   r„  r  r<  r�  r   r�  r¬   r	  r
  )r#  Ú	CENTRO_IDZdatos_alerta_no_revisadar’   r€  r8  r^  r­   rq   rq   rr   Ú"actualizar_fin_estado_alerta_ITGSMa  s"    

rá  z/<SERVICE>/post_fallasc              
   C   s´   t ƒ }| }tj}zP|g kr>t|||ƒ tdd|› �iƒdfW S tdƒ tdd|› �iƒdfW S W nN tk
r® } z0td|jj› d|› �ƒ tdd	iƒdf W Y ¢S d }~X Y nX d S )
Nré   z6Se han recibido correctamente las fallas del servicio rH  z/No se han recibido datos de fallas del servicioz1 No se han recibido datos de fallas del servicio rô   ú>No se han enviado correctamente las fallas por error en linea r€  z4 No se han enviado correctamente las fallas a ITGSM )	r/   r   r  r  r   rm   r¬   r	  r
  )r#  r’   r  r  r­   rq   rq   rr   Úpost_fallas‹  s    rã  z2/<SERVICE>/fallas_activas/<CENTRO>/<AREA>/<REGION>c              
   C   s¶   t ƒ }| ¡ }| ¡ }| ¡ }|› d|› d|› �}td|› �ƒ z"t|| |ƒ}tdƒ t|ƒdfW S  tk
r° } z0td|jj› d|› �ƒ tddiƒd	f W Y ¢S d
}~X Y nX d
S )zƒ try:
        print(f"faia{REGION[0]=}")
        print(f"faia{REGION[1]=}")
    except:
        print("NO SE PUEDE SEPRAR REGION") rÛ   úcentro_id: z-Se han enviado correctamente las fallas al FErH  râ  r€  ré   z2 No se han enviado correctamente las fallas al FE rô   N)r/   r   rm   r,  r   r¬   r	  r
  )r#  rd  rc  rb  r’   rÀ   Zfallas_activasr­   rq   rq   rr   Úfallas_to_feœ  s    rå  z/<SERVICE>/revision_fallac           	   	   C   s4  t ƒ }tdƒ tj}td|› d�ƒ |�r |d }|d }|�rg g dœ}|D ]ˆ}|d }|d }td	ƒ t| ||d
|ƒ z0t|| ||d
|ƒ t|| |ƒ |d  |¡ W qN tk
rÔ   tdƒ |d  |¡ Y qNX qN|rütd|›�ƒ td|dœƒdfS tddiƒdfS ntddiƒdfS ntddiƒdfS d S )NzREVISANDO FALLAS****-*-*-*-zdatos_falla_revisada: r½  rf  r  rÔ  rÐ   r"  zVariables en falla:r×  rÖ  rØ  rÕ  zfallas ids_dict=rÙ  rÚ  rH  ré   rÛ  rô   rÜ  r�  rÝ  )	r/   rm   r   r  r;  rŽ  rÃ   r¬   r   )	r#  r’   Zfallas_revisadaZdata_fallas_revisadasrÀ   rÞ  r+  r8  r^  rq   rq   rr   Úrevisar_falla_ITGSM²  s@    
þýræ  Úmetadata_generadoresc              
   C   sØ   |  d¡}|  di ¡}|r|s*tdƒ dS | t }| d¡d }||› d|› � }g }| ¡ D ]L\}	}
|
  dg ¡}|	d	kr„td
ƒ q^| t|	|dœd|	||dœidd�¡ q^|rÔ| |¡}td|j› d|j	› d�ƒ dS )aU  
    Guarda la metadata de generadores en Mongo.
    Cada documento mantiene: generator_name, quadrants, centro_id.
    
    payload ejemplo:
    {
      "centro": "Fonchi-Richi-Salva",
      "data": {
        "generator_1": {"quadrants": ["quadrant_1", "quadrant_2"]},
        "generator_2": {"quadrants": ["quadrant_3"]}
      }
    }
    r  rf  u&    Datos invÃ¡lidos, no se guardÃ³ nada.NrÛ   r›  r¾  Ú	quadrantsÚ0z+bug conocido: Nombre de generador invalido )Úgenerator_namerÀ   rQ  )rê  rè  rÀ   Tr”  u   âœ… Generadores guardados: z modificados, z insertados.)
r�   rm   rE  rÜ   rà   rÃ   r'   rˆ  r•  r–  )r’   Úpayloadr>  rÀ   Z
generatorsrP  r¥  rÂ  rŠ  Zgen_nameZgen_inforè  r—  rq   rq   rr   Úguardar_generadores_metadataî  s8    
ýùÿ
rì  z/<SERVICE>/post_generadoresc                 C   sT   t dƒ tj}t d|›�ƒ | d¡}| d¡}t d|›�ƒ tƒ }t||d� dS )Nz>=============== ENTRANDO A RECIBIR GENERADORES ===============zgenerators_received_data=r  rf  zgenerators_data=)rë  )ZOKrH  )rm   r   r  r�   r/   rì  )r#  Zgenerators_received_datarÀ   Zgenerators_datar’   rq   rq   rr   Úpost_generadores_desde_local"  s    

rí  z/<SERVICE>/post_umbralesc                 C   sÒ   |   ¡ }tj}tƒ }d|k}|r(tdƒ |dkr|tj}|g krbt|ƒ t|||ƒ tddiƒdfS tdƒ tddiƒd	fS nR|d
krÎtd|›d�ƒ |r¶t|||d� tddiƒdfS tdƒ tddiƒd	fS d S )NrS  zES VERSION ITG ANECrg   ré   ú*Se han enviado correctamente los umbrales rH  z$No se han recibido datos de umbralesú5 No se han enviado correctamente los umbrales a ITGSMrô   r™  zPost_umbrales Nanoox umbrales=r5  r9  )	rž  r   r  r/   rm   r   r­  r   r¸  )r#  r  rë  r’   rƒ  rq   rq   rr   Úpost_umbrales_desde_local5  s*    rð  z/<SERVICE>/def_umbrales_regionc                 C   sn   t ƒ }|  ¡ }tj}|dkrjtd|›d�ƒ |rRtƒ }t|||ƒ tddiƒdfS tdƒ tddiƒd	fS d S )
NÚSCAPPzPost_umbrales Scapp umbrales=r5  ré   rî  rH  z*No se han recibido datos de umbrales Scapprï  rô   )r   rž  r   r  rm   r/   rÃ  r   )r#  rŒ   r  rë  r’   rq   rq   rr   Úpost_umbrales_desde_scapp_local`  s    rò  z=/<SERVICE>/obtener_umbrales_actuales/<CENTRO>/<AREA>/<REGION>c           	      C   s¶   |  ¡ }|  ¡ }|  ¡ }|› d|› d|› �}tƒ }|t }|t }| dkrbt|| |ƒ}t|ƒdfS | dkrŒt|ƒ}t||dd�}t|ƒdfS | dkr²t|ƒ}t||ƒ}t|ƒdfS d S )NrÛ   rg   rH  r™  Tr9  rñ  )	r   r/   rE  rÁ  rÉ  r   rµ  rJ  rº  )	r#  rd  rc  rb  rÀ   r’   rP  Úscapp_dbrë  rq   rq   rr   Úobtener_umbrales_fes  s$    
rô  z!/<SERVICE>/post_notas/<CENTRO_ID>c              
   C   s¾   t ƒ }| }tj}t|ƒ}zR|g krHt||||ƒ tdd|› �iƒdfW S tdƒ tdd|› �iƒdfW S W nN tk
r¸ } z0td|jj	› d|› �ƒ tdd	iƒdf W Y ¢S d }~X Y nX d S )
Nré   z0Se han recibido datos de las notas del servicio rH  z!No se han recibido datos de notasz0 No se han recibido datos de notas del servicio rô   z=No se han enviado correctamente las notas por error en linea r€  z3 No se han enviado correctamente las notas a ITGSM )
r/   r   r  rµ  r  r   rm   r¬   r	  r
  )r#  rà  r’   r  r  rÀ   r­   rq   rq   rr   Ú
post_notasŠ  s    rõ  zC/<SERVICE>/post_estado_servicio_por_centro/<CENTRO>/<AREA>/<REGION>c                 C   sø   t j}| ¡ }| ¡ }| ¡ }|› d|› d|› �}td|› �ƒ tƒ }zDt|| ¡ |ƒ td|› d| › �ƒ tdd|› d| › d�iƒdfW S  tk
rò } zJtd|› d| › d	|j	j
› d
|› �ƒ tdd|› d| › d�iƒdf W Y ¢S d }~X Y nX d S )NrÛ   z#centro_id_post_estado_desde_local: ú>Se ha recibido correctamente el estado de servicio del centro ú para el servicio ré   rù   rH  úANo Se ha recibido correctamente el estado de servicio del centro rÞ  r€  úB No Se ha recibido correctamente el estado de servicio del centro rô   )r   r  r   rm   r/   rË  re  r   r¬   r	  r
  )r#  rd  rc  rb  r3  rÀ   r’   r­   rq   rq   rr   Úrecepcion_estado_centroœ  s     $rú  z"/estado_servicio_2/<AREA>/<REGION>c              
   C   s  z
t ƒ }W n0 tk
r: } ztd|› �ƒ W 5 d}~X Y nX tƒ }z\t||ƒ}t|ƒ}t||ƒ}t||ƒ}t||ƒ}	t	||	ƒ}
td|
›�ƒ tƒ  t
|
ƒdfW S  tk
� rþ } z@ddl}td|› �ƒ | ¡  t
ddt|ƒ› �iƒd	f W Y ¢S d}~X Y nX dS )
uV   
    Endpoint principal. Orquesta la obtenciÃ³n de servicios, estados y permisos.
    úError auth: Nú
respuesta=rH  r   úError en estado_servicio: ré   úError interno: rú   ©r   r¬   rm   r/   r~  rB  r  rC  r›  r©  r   r§  r¨  r  )rc  rb  rŒ   r­   r’   Úservicios_usuarioÚestructura_baseÚestados_actualesÚestados_consolidadosrT  r(  r§  rq   rq   rr   Úestado_servicio±  s(    
 




r  z/estado_servicio_iosc            
   
   C   s  z
t ƒ } W n0 tk
r: } ztd|› �ƒ W 5 d}~X Y nX tƒ }z\t|| ƒ}t|ƒ}t||ƒ}t||ƒ}t|| ƒ}t	||ƒ}td|›�ƒ tƒ  t
|ƒdfW S  tk
� rþ } z@ddl}	td|› �ƒ |	 ¡  t
ddt|ƒ› �iƒd	f W Y ¢S d}~X Y nX dS )
uZ   
    Endpoint principal iOS. Orquesta la obtenciÃ³n de servicios, estados y permisos.
    rû  Nrü  rH  r   rý  ré   rþ  rú   rÿ  )
rŒ   r­   r’   r   r  r  r  rT  r(  r§  rq   rq   rr   Úestado_servicio_iosØ  s(    
 




r  z1/<SERVICE>/estado_centro/<CENTRO>/<AREA>/<REGION>c           
   
   C   sð   |  ¡ }|  ¡ }|  ¡ }|› d|› d|› �}td|› �ƒ tƒ }| dkrìzHt||ƒ}d }td|› �ƒ tdt||ƒ› �ƒ t||ƒ}t|ƒdfW S  tk
rê }	 z<td|› d|	jj› d	|	› �ƒ td
d|› �iƒdf W Y ¢S d }	~	X Y nX d S )NrÛ   rä  rg   zestado_enviro:zestado_centro: rH  z Error solicitando estado centro rê  r€  ré   rô   )	r   rm   r/   r0  r3  r   r¬   r	  r
  )
r#  rd  rc  rb  rÀ   r’   Zestado_servicio_enviroZestado_servicio_nanooxr¸  r­   rq   rq   rr   Úget_estado_centro   s"    

r  z/<PAGE>/consolidado_estados)ÚPAGEc              
   C   s˜   t d| › d�ƒ z4tƒ }tƒ }t||| ƒ}t d|› �ƒ t|ƒdfW S  tk
r’ } z0t d|jj› d|› �ƒ tddiƒd	f W Y ¢S d
}~X Y nX d
S )zK
    Envia JSON con estados consolidados de centros, areas y regiones.
    z---------PAGE RECIBIDA-------: r½  zconsolidado_estados new: rH  z.Error obteniendo consolidado estados en linea r€  ré   z$Error obteniendo consolidado estadosrú   N)rm   r/   r   r<   r   r¬   r	  r
  )r  r’   rŒ   Zconsolidador­   rq   rq   rr   Úconsolidado_estados_por_empresa  s    r  z9/<SERVICE>/post_estado_variables/<CENTRO>/<AREA>/<REGION>c                 C   sô   t j}| ¡ }| ¡ }| ¡ }|› d|› d|› �}td|› �ƒ tƒ }z@t|||ƒ td|› d| › �ƒ tdd|› d| › d�iƒdfW S  tk
rî } zJtd|› d| › d	|jj	› d
|› �ƒ tdd|› d| › d�iƒdf W Y ¢S d }~X Y nX d S )NrÛ   z-centro_id_post_estado_variables_desde_local: rö  r÷  ré   rù   rH  rø  rÞ  r€  rù  rô   )
r   r  r   rm   r/   rÍ  r   r¬   r	  r
  )r#  rd  rc  rb  r  rÀ   r’   r­   rq   rq   rr   Úrecepcion_estado_variables)  s     $r	  z>/<SERVICE>/estados_variables_actuales/<CENTRO>/<AREA>/<REGION>c           
   
   C   sÜ   |  ¡ }|  ¡ }|  ¡ }|› d|› d|› �}tƒ }|t j}| d|iddddddœ¡}z0t|ƒ}|r†|d }tdƒ t|d�dfW S W nN tk
rÖ }	 z0td	|	j	j
› d
|	› �ƒ tddiƒdf W Y ¢S d }	~	X Y nX d S )NrÛ   rÀ   r   rŽ   )rÐ   r2  rÄ  rÀ   rã  zDSe han enviado correctamente las variables en mal estado hacia el FE©rÒ  rH  zONo se han enviado correctamente las variables en mal estado por error en linea r€  ré   zI No se han enviado correctamente las variables en mal estado hacia el FE rô   )r   r/   r„  rð  rÂ   rÞ   rm   r   r¬   r	  r
  )
r#  rd  rc  rb  rÀ   r’   rÌ  r?  rå  r­   rq   rq   rr   Úget_var_state;  s0    
ûþr  z0/<SERVICE>/tipo_control/<CENTRO>/<AREA>/<REGION>c           	   
   C   sÆ   |  ¡ }|  ¡ }|  ¡ }|› d|› d|› �}z8tƒ }|t }t||ƒ}td|› d�ƒ t|d�dfW S  tk
rÀ } z>td|› d|jj› d|› �ƒ td	d
|› d�iƒdf W Y ¢S d }~X Y nX d S )NrÛ   z;Se ha obtenido correctamente el tipo de control del centro rù   r
  rH  z>No se ha obtenido correctamente el tipo de control del centro rÞ  r€  ré   z> No se ha enviado correctamente el tipo de control del centro z hacia el FE rô   )	r   r/   rE  rA   rm   r   r¬   r	  r
  )	r#  rd  rc  rb  rÀ   r’   rP  rR  r­   rq   rq   rr   Úget_tipo_controlZ  s    
r  z0/scapp/mirror_analytics/<REGION>/<AREA>/<CENTRO>c              
   C   sp  t  ¡ }tdƒ ||| f}t  ¡  ¡ }|  ¡ } | ¡ }| ¡ }|› d|› d| › �}tj}tj}tj|tj	d�}|r€td|› �ƒ znt
ƒ }	|	t }
t|
||ƒ td|||ƒ td|› �ƒ t  ¡ }td||  ¡ d d	›d
�ƒ tddiƒdfW S  tk
�rj } z\td|› d|jj› d|› �ƒ t  ¡ }td||  ¡ d d	›d
�ƒ tddiƒdf W Y ¢S d}~X Y nX dS )a¯  
    Recepcion de datos o coleccion de pendientes desde locales Scapp
    Input Format:
    {{"timestamp": {
        "$date": "2025-05-13T11:24:00.000Z"
    },
    "camera_id": "4-A",  # ID de la camara o sensor origen de los datos

    "data": {
        "name": "4",  # Nombre o ID interno de la camara

        "activity_data": [  # Lista cronologica de mediciones de actividad
        {
            "time": "2025-04-28T07:45:00.999000",  # Timestamp (ISO 8601)
            "value": 54.85                         # Valor de actividad (float)
        },
        ...
        ],

        "alarms_by_tasa": {  # Conteo de alarmas por nivel de tasa
        "baja": 0,
        "media": 0,
        "alta": 0
        },

        "alarms_by_tasa_levels": {  # Umbrales utilizados para clasificar las tasas
        "baja": [0, 8],
        "media": [12],
        "alta": [22.11]
        },

        "alarms_data": [],  # Lista de alarmas detalladas (actualmente vacia)

        "feeding_time_range": {  # Intervalo detectado de alimentacion
        "inicio": "2025-04-28T11:26:42.882000",
        "final": "2025-04-28T14:07:17.477000"
        },

        "tasa_data": [  # Serie temporal de valores de tasa
        {
            "time": "2025-04-28T07:30:00.999000+00:00",
            "value": 0
        },
        ...
        ],

        "tasa_values": [  # Conjunto de valores unicos de tasa observados
        0, 8, 22.11, 12
        ],

        "values_summary": {  # Resumen estadistico del proceso
        "alarms_by_ton": 0,        # Conteo de alarmas por tonelada
        "alarms_count": 0,         # Total de alarmas detectadas
        "alarms_threshold": 3,     # Umbral minimo para considerar una alarma
        "delivered_food": 3123.34, # Cantidad total de comida entregada (kg)
        "fasts_count": 0,          # Numero de ayunos detectados
        "perdidos_count": 0,        # Conteo de eventos perdidos
        "sfr_value": 57,           # Valor SFR (indicador especifico del sistema)
        "tasa_units": "kg/min",    # Unidades usadas para tasa
        "visitas_count": 1          # Numero de visitas detectadas
        }
    },

    "_id": {
        "$oid": ""  # ID unico del documento en MongoDB
    }}
    zENTRANDO A MIRROR ANALYTICS 
rÛ   ©Úobject_hookzJSON recibido desde rc   z:Se ha guardado exitosamente la analitica Scapp del centro z Datos de Analitica guardados en ç     @�@z.4fzms.ré   z<Datos de analitica Scapp recibidos exitosamente por servidorrH  z=No se ha guardado correctamente a analitica Scapp del centro rÞ  r€  z!Datos de Analitica procesados en z*Error interno guardando datos de analiticarú   N)r   r‡  rm   r~  r   r   r  Úloadsr-   r  r/   rÁ  Úbulk_scapp_analyticsr   r  r   r¬   r	  r
  )rd  rc  rb  Út1r€  r�  rÀ   r‚  Zproccess_jsonr’   ró  Zt_endr­   rq   rq   rr   Úscapp_analytics_savingm  s6    E
r  c                 C   s�  t | ƒ}tdt|ƒ›�ƒ t|tƒr,|g}nt|tƒr<|}ntdƒ‚g }t ¡ }|D ]ú}tdt|ƒ›d�ƒ td| 	¡ ›�ƒ | 
d¡}| 
d¡}	t|tƒsÞzt |¡}W n2 tk
rÜ }
 ztd|›�ƒ|
‚W 5 d	}
~
X Y nX |	d	krîtd
ƒ‚|jpøtj}t|j|j|j|d�}||	|dœ}dd„ | ¡ D ƒ|||dœ–}| t||dd�¡ qT|�rŒ|j|dd�}td|› dt|ƒ› d|j› d|j› �ƒ d	S )uÈ   
    Acepta received_json como dict o lista de dicts.
    Para cada documento normaliza el timestamp al inicio del dÃ­a y reemplaza
    el registro correspondiente a centro_id + camera_id + dÃ­a.
    ztype(received_json)=z,received_json debe ser dict o lista de dictsztype(doc_in)=rù   zdoc_in.keys()=r  Ú	camera_idu   timestamp invÃ¡lido: Nz-Falta 'camera_id' en alguno de los documentos)Útzinfo)rÀ   r  r  c                 S   s   i | ]\}}|d kr||“qS rè  rq   r¾  rq   rq   rr   r6    s       z(bulk_scapp_analytics.<locals>.<dictcomp>)rÀ   r  ÚupdatedTr”  r¦  r  z -> documentos recibidos: z, modificados: z, insertados: )r2   rm   r‰   r  r  rÞ   r(  r   r‡  rR  r�   Zfromisoformatr¬   r  r   ZutcÚyearÚmonthr–  rà   rÃ   r*   rˆ  rû   r•  r–  )ró  r‚  rÀ   rb  ÚdocsZopsZ
updated_tsZdoc_inrT  Zcamr­   ZtzÚ	start_dayrL  Znew_docr—  rq   rq   rr   r  Ú  sL    




"ýü"ÿr  z,/scapp/mirror_notas/<REGION>/<AREA>/<CENTRO>c           
   
   C   sn  |  ¡ }|  ¡ }|   ¡ } t||| ƒ}tjd k	rHtjtkrHtddiƒdfS z,tj}t|tƒrjtj	|t
jd�}t|ƒ}W nX tttjfk
rÌ } z2td|› d|› �ƒ tdt|ƒdœƒd	f W Y ¢S d }~X Y nX zDtƒ }|t }t|||ƒ}	td
|› d|	› d�ƒ td|	dœƒdfW S  tk
�rh } z6td|› d|jj› d|› �ƒ tddiƒdf W Y ¢S d }~X Y nX d S )Nré   u,   Payload de notas excede el tamaÃ±o permitidoi�  r  zPayload de notas invalido de rø   z$Notas recibidas con sintaxis erronea©ré   Údetailrë   z"Notas guardadas exitosamente para r   z/Notas Scapp recibidas exitosamente por servidor)ré   ÚsavedrH  zError guardando notas de ú linea z)Notas recibidas erroneamente por servidorrú   )r   rM   r   Zcontent_lengthr\   r   r  r  r  r  r-   r  r`   r(  rI  ÚJSONDecodeErrorrm   r/   rÁ  r_   r¬   r	  r
  )
rd  rc  rb  rÀ   r‚  r  r­   r’   ró  r  rq   rq   rr   Úscapp_notes_saving  s.    
,r   z3/scapp/mirror_feeder_score/<REGION>/<AREA>/<CENTRO>c           
   
   C   sb  t  ¡ }| ¡ }| ¡ }|  ¡ } t||| ƒ}z,tj}t|tƒrNtj|t	j
d�}t|ƒ}W nX tttjfk
r° } z2td|› d|› �ƒ tdt|ƒdœƒdf W Y ¢S d}~X Y nX zTtƒ }|t }	t|	||ƒ td|› d	t  ¡ |  ¡ d
 d›d�ƒ tddiƒdfW S  tk
�r\ } z6td|› d|jj› d|› �ƒ tddiƒdf W Y ¢S d}~X Y nX dS )z™
    Recepcion de datos FeederScore desde locales Scapp.
    El cliente actual envia JSON doble-serializado: request.json es un string con la lista.
    r  z FeederScore payload invalido de rø   z$Datos recibidos con sintaxis erronear  rë   Nz'FeederScore guardado exitosamente para z (r  z.2fzms).ré   z?Datos de feeder score Scapp recibidos exitosamente por servidorrH  zError guardando FeederScore de r  r|  rô   )r   r‡  r   rM   r   r  r  r  r  r-   r  rV   r(  rI  r  rm   r   r/   rÁ  rU   r  r¬   r	  r
  )
rd  rc  rb  r  rÀ   r‚  r  r­   r’   ró  rq   rq   rr   Úscapp_feeder_score_saving8  s,    
,(r!  z/scapp/last_received_datac               
   C   s¢  t dƒ d } z(tj d¡} t| ƒ} t dtj›�ƒ W n8 tk
rl } zt |jj› d|› �ƒ W 5 d }~X Y nX | sŠt dƒ tddiƒdfS t	ƒ }z¶t
ƒ }|t d	 }t|| |ƒ}t d
|›�ƒ |d krðt|| d ƒ}|d krðtddd dœƒdfW S | ¡ t ¡  ¡ k}|�r"|tdd� }| ¡ }nd }t dƒ t| ¡ ||dœƒdfW S  tk
�rœ } z6t d| › d|jj› d|› �ƒ tddiƒdf W Y ¢S d }~X Y nX d S )NzEntrando a SCAPP-LRDrÀ   zrequest.args=r€  z"error:Falta el parametro centro_idru   úFalta el parametro centro_idrë   Údata_analyticzLRD: ts=úSin registrosF©rã  ÚonlineZupcomingéÎ   rŽ   rÍ  zSCAPP-LRD Data generadarH  z2No se ha obtenido el ultimo dato Scapp del centro rÞ  rÌ  ú!Datos no encontrados por servidorrú   )rm   r   rÙ  r�   r  r¬   r	  r
  r   Úget_start_of_todayr/   rÁ  Úfetch_last_timestamp_for_centroÚfetch_last_timestamp_overallr—  r   r‡  r   Ú	isoformat)rÀ   r­   Zstart_todayr’   Zanalytic_collrT  r&  Úupcoming_tsrq   rq   rr   Úlast_received_dataY  sV    (ýü
ýür.  z!/scapp/last_received_feeder_scorec               
   C   s8  t j d¡} | s tddiƒdfS zt| ƒ}W n: tk
rf } ztdt|ƒiƒdf W Y ¢S d }~X Y nX zttƒ }|t }t	||ƒ}|d kr tddd dœƒdfW S |t
ƒ k}|rÀ|td	d
�  ¡ nd }t| ¡ ||dœƒdfW S  tk
�r2 } z6td| › d|jj› d|› �ƒ tddiƒdf W Y ¢S d }~X Y nX d S )NrÀ   ru   r"  rë   r$  Fr%  r'  rŽ   rÍ  rH  z3No se ha obtenido el ultimo FeederScore del centro rÞ  r€  rÌ  r(  rú   )r   rÙ  r�   r   rO   r(  r  r/   rÁ  rT   r)  r   r,  r¬   rm   r	  r
  )Zcentro_id_paramrÀ   r­   r’   ró  Zreceived_atr&  r-  rq   rq   rr   Úlast_received_feeder_score’  s>    *
ýü
ýür/  )Úreturnc                  C   s   t  ¡ } t | j| j| jd�S )zf
    Devuelve un datetime (naive) con la fecha de hoy a las 00:00
    segun el reloj del sistema.
    )r  r  r–  )r   r‡  r  r  r–  )r‡  rq   rq   rr   r)  ´  s    r)  )rÀ   Ú
start_timec                 C   s`   d|d|idœidddiiddid	d
ddœig}t |  |¡ƒ}td|›�ƒ |r\|d
 d S dS )zO
    Retorna el timestamp mas reciente para el centro_id desde start_time.
    r  rs  ©rÀ   r  z$sortr  r›  z$limitrŽ   r  r   )rÐ   r  z
LRD: docs=N)rÞ   r'  rm   )r§  rÀ   r1  r)  r  rq   rq   rr   r*  ½  s    þ
ù	r*  c                 C   sT   |ddidœ}|dk	r"||d d< |   |¡ dd¡ d¡}t|dƒ}|rP|d S dS )	zj
    Si start_time esta dado, filtra >= start_time; si no, toma el mas reciente en toda la coleccion.
    r“  Tr2  Nr  rs  r›  rŽ   )rÂ   rû  Úlimitr«  )r§  rÀ   r1  rÅ   rÖ   rÔ   rq   rq   rr   r+  Ï  s    þ
r+  ©rÀ   Úscope_prefixc                C   s    t | t ||t|d� ||d�S )Nrƒ   r4  )r^   r]   r   )ró  r  Ú
day_rangesrÀ   r5  rq   rq   rr   Ú_fetch_scapp_notesà  s    ûr7  c                 C   s   | pi |dœS )N©Úanalytic_dataÚnotesrq   r8  rq   rq   rr   Ú_analytics_notes_responseê  s    þr;  zN/scapp/get_notas_center_data/<REGION>/<AREA>/<CENTRO>/<START_DAY>/<DAY_RANGES>c              
   C   sÚ   t |ƒ}t|ƒ}|s*tdd|› �iƒdfS |sDtdd|› �iƒdfS t||| ƒ}z0tƒ }|t }	t|	|||d�}
td|
iƒdfW S  tk
rÔ } z6td|› d	|j	j
› d
|› �ƒ tddiƒdf W Y ¢S d}~X Y nX dS )u]   Consulta independiente para integraciones; el frontend usa la respuesta analÃ­tica unificada.rÌ  úIParametros de dias en formato no valido-Se esperaba 'DD-MM-YYYY' y llego rë   ú2Parametros de rango de dias en formato no valido: rÑ   r:  rH  zError consultando notas de r  rø   z!Notas no encontradas por servidorrú   N)Úvalidar_y_convertir_fechaÚvalidar_y_convertir_dias_desder   rM   r/   rÁ  r7  r¬   rm   r	  r
  )rd  rc  rb  Ú	START_DAYÚ
DAY_RANGESr  r6  rÀ   r’   ró  r:  r­   rq   rq   rr   Úscapp_get_notes_center_datañ  s    rB  zQ/scapp/get_analytic_center_data/<REGION>/<AREA>/<CENTRO>/<START_DAY>/<DAY_RANGES>c              
   C   s   |   ¡ } |  ¡ }|  ¡ }|}|}td|›�ƒ td|›�ƒ t|ƒ}t|ƒ}|sftdd|› �iƒdfS |s€tdd|› �iƒdfS |› d|› d| › �}	i }
d}z¨tƒ }|t }t|	|||
|ƒ}zt||||	d	�}W n< t	k
�r } ztd
|	› d|› �ƒ g }W 5 d}~X Y nX |�r$td|	› �ƒ ntd|	› �ƒ tt
||ƒƒdfW S  t	k
�rš } z6td|	› d|jj› d|› �ƒ tddiƒdf W Y ¢S d}~X Y nX dS )zØ
    Ruta de comunicacion con FE para obtener datos de analitica por centro y por dia, a partir de una fecha inicial y un rango de dias desde esa fecha
    TODO: Insertar ejemplo formato de entrada y salida
    
    zLDRd fecha_str=zLDRd ranges_str=rÌ  r<  rë   r=  rÛ   TrÑ   z'Error cargando notas para analitica de rø   Nz:Se ha generado exitosamente la analitica Scapp del centro z5No hay informacion de analitica Scapp para el centro rH  z=No se ha generado correctamente a analitica Scapp del centro rÞ  r€  ú)Datos generados erroneamente por servidorrú   )r   rm   r>  r?  r   r/   rÁ  rI   r7  r¬   r;  r	  r
  )rd  rc  rb  r@  rA  rŠ  Ú
ranges_strr  r6  rÀ   Úscapp_configsÚ
parse_datar’   ró  Zmultiple_analytic_daysr:  Únotes_errorr­   rq   rq   rr   Úscapp_get_analytic_center_data  sJ    þýrH  z/scapp_get_centers_accessc               
   C   s²   z&t ƒ } tƒ }|t t }t|| ƒ}W nZ tk
r€ } z<td| › d|jj› d|› �ƒ tdd| › �iƒdf W Y ¢S d}~X Y nX |r–td|iƒd	fS tdd
| › d�iƒdfS dS )zB
    Valida y retorna permisos de usuario para analitca Scapp
    zMNo se han obtenido correctamente los permisos de analitica Scapp del usuario rÞ  r€  rÌ  z:No se han obtenido correctamente los permisos del Usuario rô   Nr¦  rH  zUsuario z. no posee permisos visualizar datos de centrosrB  )	r   r/   r�   Úscapp_analytics_centersr¬   rm   r	  r
  r   )rŒ   r’   r“   Zavailable_centersr­   rq   rq   rr   Úget_analytic_centers;  s    ,rJ  c              
   C   sz   z.t d| ›�ƒ t | d¡}t|j|j|jƒW S  tk
rt } z(t d| › d|jj› d|› �ƒ W Y ¢dS d}~X Y nX dS )zw
    Verifica que la fecha venga en el formato correcto y la convierte al formato datetime. De fallar retorna None
    z
fecha_str=z%d-%m-%Yz<Formato de fecha invalido. Se esperaba 'DD-MM-YYYY' y llego rø   r©  N)	rm   r   rõ  r  r  r–  r¬   r	  r
  )rŠ  Zfecha_dtr­   rq   rq   rr   r>  P  s    r>  c              
   C   s€   z0t | ƒ}|dkr|W S td| › d�ƒ W dS W nJ tk
rz } z,tdt| ƒ› d|jj› d|› �ƒ W Y ¢dS d}~X Y nX dS )zt
    Verifica que el rango de dias venga en el formato correcto y la convierte a entero. De fallar retorna None
    r   zError: Rango= z menor a 1 para rango de dias.Nz#Formato erroneo para rango de dias rø   r©  )rÈ  rm   r¬   r‰   r	  r
  )rÚ   Z
range_daysr­   rq   rq   rr   r?  _  s    
"r?  z/scapp/compare_analytic_centersc                  C   s.  t j dd¡} t j d¡}t j d¡}|r.|s>tddiƒdfS zt|ƒ}t|ƒ}W n$ tk
rv   tddiƒdf Y S X |r€|s�tdd	iƒdfS d
d„ |  d¡D ƒ}td|›�ƒ t	|ƒdk sÊt	|ƒdkrÚtddiƒdfS zöt
ƒ }|t }i }d}	g }
|D ]È}|}zt|ƒ}W n" tk
�r0   t d|¡ Y nX ||k�rJt d||¡ t|||||	ƒ}zt|||t|ƒd�}W n< tk
�r® } ztd|› d|› �ƒ g }W 5 d}~X Y nX |
 |||dœ¡ qút|
ƒdfW S  tk
�r( } z8|jj}d|› d|› �}t|ƒ td|iƒdf W Y ¢S d}~X Y nX dS )a[  
    Ruta de comunicacion con FE para obtener datos de versus de analitica por centro y por dia, a partir de una fecha inicial y un rango de dias desde esa fecha
    
    _old: Recibe una lista de centro_id, fecha de inicio y rango y retorna los datos de analitica para multiples centros
    TODO: Insertar ejemplo formato de entrada y salida
    r/  r^  r  r6  ru   ú(Faltan parametros start_day o day_rangesrë   zGEl parametro start_day debe estar en formato DD-MM-YYYY, ej: 10-05-2025z7Los parametros start_day y day_ranges deben ser validosc                 S   s   g | ]}|  ¡ r|  ¡ ‘qS rq   ©r_  ©rÓ   rè  rq   rq   rr   rÕ   Ž  s      z,compare_analytic_centers.<locals>.<listcomp>rÅ  zcentros_list=rÙ  r´  z<Debes especificar entre 2 y 4 centros, ej: ?centros=C1,C2,C3TzGscapp.comparacion_sin_normalizar centro=%s motivo=formato_no_reconocidoz3scapp.comparacion_normalizada centro=%s consulta=%srÑ   z)Error cargando notas para comparacion de rø   N©Únamer9  r:  rH  úError en linea ré   rú   )r   rÙ  r�   r   r>  r?  r(  rÜ   rm   rû   r/   rÁ  rO   r   rt   rs   rI   r7  r¬   rÃ   r	  r
  )Úcentros_strrŠ  rD  r  r6  Úcentros_listr’   ró  rE  rF  Úresponse_listrÀ   Zcentro_consultarÒ  r:  rG  r­   Úlinearp   rq   rq   rr   Úcompare_analytic_centerso  s’    	 ÿþ
 ÿþ ÿþ
   þü
ý
rU  c           
      C   sÈ   g }t | |ƒ}g }| ¡ D ]�}|| D ]‚}|| | D ]p}|| | |  d¡}t|tƒrbd|krl| |¡ t|tƒr€| d¡nd}	|	r6| d t| d¡ƒ¡ 	¡ ¡ q6q&q|rÄt
 d|d |¡¡ |S )z�
    A partir del nombre de usuario, obtiene y retorna los permisos para ese usuario
    TODO: Insertar ejemplo formato de entrada y salida
    rc   r¢   FrÛ   zKscapp.permiso_sin_status usuario=%s centros=%s (omitidos del listado SCAPP)rÅ  )r¹   rR  r�   r  r  rÃ   rÍ  ÚreversedrÜ   rÏ  r   rt   )
r“   rŒ   rT  Zpermisos_centroZdefectuososrä   r  r  Zbloque_scappZstatus_scapprq   rq   rr   rI  Æ  s$    

$ ÿrI  zF/scapp/get_analytic_area_data/<REGION>/<AREA>/<START_DAY>/<DAY_RANGES>c              
   C   sn  |   ¡ } |  ¡ }|› d| › �}|}|}t|ƒ}t|ƒ}|sPtdd|› �iƒdfS |sjtdd|› �iƒdfS i }	d}
z tƒ }|t }t|||ƒ}zt||||d�}W n: tk
rÜ } zt	d|› d	|› �ƒ g }W 5 d
}~X Y nX |ròt	d|› �ƒ nt	d|› �ƒ tt
||ƒƒdfW S  tk
�rh } z6t	d|› d|jj› d|› �ƒ tddiƒdf W Y ¢S d
}~X Y nX d
S )aM  
    Ruta de comunicacion con FE para obtener datos de analitica por area y por dia, a partir de una fecha inicial y un rango de dias desde esa fecha
    _old: Recibe un area_id, fecha de inicio y rango de dias y retorna los datos de analitica del area solicitada por dia 

    TODO: Insertar ejemplo formato de entrada y salida
    rÛ   rÌ  r<  rë   r=  T©r5  z-Error cargando notas para analitica del area rø   Nz8Se ha generado exitosamente la analitica Scapp del area z3No hay informacion de analitica Scapp para el area rH  z;No se ha generado correctamente a analitica Scapp del area rÞ  r€  rC  rú   )r   r>  r?  r   r/   rÁ  rJ   r7  r¬   rm   r;  r	  r
  )rc  rb  r@  rA  r�  rŠ  rD  r  r6  rE  rF  r’   ró  Zmultiple_analytic_area_daysr:  rG  r­   rq   rq   rr   Úscapp_get_analytic_area_dataâ  sD    þýrX  z/scapp/compare_analytic_areasc                  C   sR  t j dd¡} t j d¡}t j d¡}t|ƒ}t|ƒ}|sPtdd|› �iƒdfS |sjtdd|› �iƒdfS d	d
„ |  d¡D ƒ}t|ƒdk s–t|ƒdkr¦tddiƒdfS �zLtƒ }|t	 }i }d}	|d }
g }|D �]}t
d|›�ƒ t
d|›�ƒ t
d|›�ƒ |}zt|ƒ}W n" tk
�r2   t d|¡ Y nX ||k�rLt d||¡ t|
|||ƒ}|�rpt
d|› �ƒ nt
d|› �ƒ zt|||t|ƒd�}W n< tk
�rÒ } zt
d|› d|› �ƒ g }W 5 d}~X Y nX | |||dœ¡ qÐt|ƒdfW S  tk
�rL } z8|jj}d|› d|› �}t
|ƒ td|iƒdf W Y ¢S d}~X Y nX dS ) ay  
    Ruta de comunicacion con FE para obtener datos de versus de analitica por por area y por dia, a partir de una fecha inicial y un rango de dias desde esa fecha
    _old: Recibe una lista de areas_id, una fecha de inicio y rango de dias. Retorna los datos de analitica para multiples areas en los dias solicitados

    TODO: Insertar ejemplo formato de entrada y salida
    r  r^  r  r6  rÌ  úNParametros de dias en formato no valido-Se esperaba 'DD-MM-YYYY' y se recibio rë   r=  c                 S   s   g | ]}|  ¡ r|  ¡ ‘qS rq   rL  rM  rq   rq   rr   rÕ   .  s      z*compare_analytic_areas.<locals>.<listcomp>rÅ  rÙ  r´  z8Debes especificar entre 2 y 4 areas, ej: ?areas=A1,A2,A3Tr#  zarea_id=z
start_day=zday_ranges=zEscapp.comparacion_sin_normalizar area=%s motivo=formato_no_reconocidoz1scapp.comparacion_normalizada area=%s consulta=%szHay datos en zSin datos en rW  z/Error cargando notas para comparacion del area rø   NrN  rH  rP  rú   )r   rÙ  r�   r>  r?  r   rÜ   rû   r/   rÁ  rm   rN   r(  r   rt   rs   rK   r7  r¬   rÃ   r	  r
  )Ú	areas_strrŠ  rD  r  r6  Ú
areas_listr’   ró  rE  rF  r§  rS  r�  Zarea_consultarÒ  r:  rG  r­   rT  rp   rq   rq   rr   Úcompare_analytic_areas  sx    	 ÿþ

ü
ý
r\  zA/scapp/get_analytic_region_data/<REGION>/<START_DAY>/<DAY_RANGES>c              
   C   sh  t ƒ }|  ¡ } | › }|}|}t|ƒ}t|ƒ}|sFtdd|› �iƒdfS |s`tdd|› �iƒdfS i }	d}
z¤|t }t||||ƒ}zt||||d�}W n: tk
rÎ } zt	d|› d|› �ƒ g }W 5 d	}~X Y nX | 
d
¡rêt	d|› �ƒ nt	d|› �ƒ t|d|i–ƒdfW S  tk
�rb } z6t	d|› d|jj› d|› �ƒ tddiƒdf W Y ¢S d	}~X Y nX d	S )zÓ
    Ruta de comunicacion con FE para obtener datos de analitica por region y por dia, a partir de una fecha inicial y un rango de dias desde esa fecha
    TODO: Insertar ejemplo formato de entrada y salida
    rÌ  rY  rë   r=  TrW  z1Error cargando notas para analitica de la region rø   Nr9  z<Se ha generado exitosamente la analitica Scapp de la Region z3No hay informacion de analitica Scapp de la Region r:  rH  z?No se ha generado correctamente a analitica Scapp de la Region rÞ  r€  rC  rú   )r/   r   r>  r?  r   rÁ  rL   r7  r¬   rm   r�   r	  r
  )rb  r@  rA  r’   rœ  rŠ  rD  r  r6  rE  rF  ró  Zmultiple_analytic_region_daysr:  rG  r­   rq   rq   rr   Úscapp_get_analytic_region_datak  sD    
 þýr]  zU/scapp/get_feeder_score_center_data/<REGION>/<AREA>/<CENTRO>/<START_DAY>/<DAY_RANGES>c              
   C   s  |  ¡ }|  ¡ }|   ¡ } t|ƒ}t|ƒ}|sBtdd|› �iƒdfS |s\tdd|› �iƒdfS t||| ƒ}z@tƒ }|t }	|	t }
t|
|||t	|d� ƒ}td|iƒdfW S  t
k
� rþ } z6td|› d	|jj› d
|› �ƒ tddiƒdf W Y ¢S d }~X Y nX d S )NrÌ  r<  rë   r=  rƒ   Úfeeder_score_datarH  z7No se ha generado correctamente FeederScore del centro rÞ  r€  rC  rú   )r   r>  r?  r   rM   r/   rÁ  rP   rS   r   r¬   rm   r	  r
  )rd  rc  rb  r@  rA  r  r6  rÀ   r’   ró  r§  Úfeeder_scorer­   rq   rq   rr   Ú"scapp_get_feeder_score_center_dataª  s0    ür`  z#/scapp/compare_feeder_score_centersc               
   C   sÆ  t j dd¡} t j d¡}t j d¡}|r.|s>tddiƒdfS t|ƒ}t|ƒ}|shtdd|› �iƒdfS |s‚tdd	|› �iƒdfS d
d„ |  d¡D ƒ}t|ƒdk s®t|ƒdkr¾tddiƒdfS zdd„ |D ƒ}W n< tk
�r } ztdt	|ƒiƒdf W Y ¢S d }~X Y nX z\t
ƒ }|t }	|	t }
|t|d� }g }|D ] }| |t|
|||ƒdœ¡ �q<t|ƒdfW S  tk
�rÀ } z6td|jj› d|› �ƒ tdd|› �iƒdf W Y ¢S d }~X Y nX d S )Nr/  r^  r  r6  ru   rK  rë   zPEl parametro start_day debe estar en formato DD-MM-YYYY, ej: 10-05-2025 y llego r=  c                 S   s   g | ]}|  ¡ r|  ¡ ‘qS rq   rL  rA  rq   rq   rr   rÕ   Û  s      z0compare_feeder_score_centers.<locals>.<listcomp>rÅ  rÙ  r´  zQDebes especificar entre 2 y 4 centros, ej: ?centros=Region-Area-C1,Region-Area-C2c                 S   s   g | ]}t |ƒ‘qS rq   )rO   )rÓ   rÀ   rq   rq   rr   rÕ   â  s     rƒ   ©rO  r^  rH  z4Error comparando FeederScore entre centros en linea r€  ré   r¡  rú   )r   rÙ  r�   r   r>  r?  rÜ   rû   r(  r  r/   rÁ  rP   r   rÃ   rS   r¬   rm   r	  r
  )rQ  rŠ  rD  r  r6  rR  Znormalized_centersr­   r’   ró  r§  Zend_dayrS  rÀ   rq   rq   rr   Úcompare_feeder_score_centersÊ  sL     ÿþ*þrb  zJ/scapp/get_feeder_score_area_data/<REGION>/<AREA>/<START_DAY>/<DAY_RANGES>c              
   C   sî   |  ¡ }|   ¡ } t|ƒ}t|ƒ}|s:tdd|› �iƒdfS |sTtdd|› �iƒdfS t|› d| › �ƒ}z.tƒ }|t }t||||ƒ}	td|	iƒdfW S  tk
rè }
 z6t	d|› d	|
j
j› d
|
› �ƒ tddiƒdf W Y ¢S d }
~
X Y nX d S )NrÌ  r<  rë   r=  rÛ   r^  rH  z5No se ha generado correctamente FeederScore del area rÞ  r€  rC  rú   )r   r>  r?  r   rN   r/   rÁ  rQ   r¬   rm   r	  r
  )rc  rb  r@  rA  r  r6  r�  r’   ró  r_  r­   rq   rq   rr   Ú scapp_get_feeder_score_area_data÷  s"    rc  z!/scapp/compare_feeder_score_areasc               
   C   s–  t j dd¡} t j d¡}t j d¡}t|ƒ}t|ƒ}|sPtdd|› �iƒdfS |sjtdd|› �iƒdfS d	d
„ |  d¡D ƒ}t|ƒdk s–t|ƒdkr¦tddiƒdfS zdd
„ |D ƒ}W n: tk
rò } ztdt	|ƒiƒdf W Y ¢S d }~X Y nX zFt
ƒ }|t }	g }
|D ] }|
 |t|	|||ƒdœ¡ �qt|
ƒdfW S  tk
�r� } z6td|jj› d|› �ƒ tdd|› �iƒdf W Y ¢S d }~X Y nX d S )Nr  r^  r  r6  rÌ  rY  rë   r=  c                 S   s   g | ]}|  ¡ r|  ¡ ‘qS rq   rL  )rÓ   r  rq   rq   rr   rÕ      s      z.compare_feeder_score_areas.<locals>.<listcomp>rÅ  rÙ  r´  zCDebes especificar entre 2 y 4 areas, ej: ?areas=Region-A1,Region-A2c                 S   s   g | ]}t |ƒ‘qS rq   )rN   )rÓ   r�  rq   rq   rr   rÕ   &   s     ra  rH  z2Error comparando FeederScore entre areas en linea r€  r¡  rú   )r   rÙ  r�   r>  r?  r   rÜ   rû   r(  r  r/   rÁ  rÃ   rQ   r¬   rm   r	  r
  )rZ  rŠ  rD  r  r6  r[  Znormalized_areasr­   r’   ró  rS  r�  rq   rq   rr   Úcompare_feeder_score_areas   sD     ÿþ*þrd  zE/scapp/get_feeder_score_region_data/<REGION>/<START_DAY>/<DAY_RANGES>c           
   
   C   sè   |   ¡ } | › }t|ƒ}t|ƒ}|s8tdd|› �iƒdfS |sRtdd|› �iƒdfS z<tƒ }|t }t||||tj 	d¡d�}t||dœƒdfW S  t
k
râ }	 z6td	|› d
|	jj› d|	› �ƒ tddiƒdf W Y ¢S d }	~	X Y nX d S )NrÌ  rY  rë   r=  r¯  )r¯  ra  rH  z9No se ha generado correctamente FeederScore de la Region rÞ  r€  rC  rú   )r   r>  r?  r   r/   rÁ  rR   r   rÙ  r�   r¬   rm   r	  r
  )
rb  r@  rA  rœ  r  r6  r’   ró  r_  r­   rq   rq   rr   Ú"scapp_get_feeder_score_region_data9   s6    
ûþýre  c                   C   s   t ddddœƒdfS )NFZgonez,Live summary fue dado de baja el 2026-07-29.)rÃ  ru   r  iš  )r   rq   rq   rq   rr   Ú_live_summary_goneZ   s    ýürf  z3/scapp/mirror_live_summary/<REGION>/<AREA>/<CENTRO>c                 C   s   t ƒ S rv   ©rf  )rd  rc  rb  rq   rq   rr   Úscapp_live_summary_savingb   s    rh  z!/scapp/last_received_live_summaryc                   C   s   t ƒ S rv   rg  rq   rq   rq   rr   Úlast_received_live_summaryg   s    ri  zU/scapp/get_live_summary_center_data/<REGION>/<AREA>/<CENTRO>/<START_DAY>/<DAY_RANGES>c                 C   s   t ƒ S rv   rg  )rd  rc  rb  r@  rA  rq   rq   rr   Ú"scapp_get_live_summary_center_datal   s    rj  z#/scapp/compare_live_summary_centersc                   C   s   t ƒ S rv   rg  rq   rq   rq   rr   Úcompare_live_summary_centersq   s    rk  zJ/scapp/get_live_summary_area_data/<REGION>/<AREA>/<START_DAY>/<DAY_RANGES>c                 C   s   t ƒ S rv   rg  )rc  rb  r@  rA  rq   rq   rr   Ú scapp_get_live_summary_area_datav   s    rl  z!/scapp/compare_live_summary_areasc                   C   s   t ƒ S rv   rg  rq   rq   rq   rr   Úcompare_live_summary_areas{   s    rm  zE/scapp/get_live_summary_region_data/<REGION>/<START_DAY>/<DAY_RANGES>c                 C   s   t ƒ S rv   rg  )rb  r@  rA  rq   rq   rr   Ú"scapp_get_live_summary_region_data€   s    rn  c                 C   sH   | t  j}dddddœ}| d|i|¡}|d }|r@||kr@dS dS d S )Nr   rÇ  rŒ   rç   TF)r�   rf   r‘   )r=  rŒ   Úregion_analytic_accessr“   rÈ  r  r  rq   rq   rr   Úregion_analytics_access„   s    
rp  c                 C   s   t  dd¡}|r| ¡  dS )z8Se ejecuta tras cada request, incluso si hubo excepcion.Ú	db_clientN©r   Úpopr¦  ©Úexcrq  rq   rq   rr   Úclose_db_request‘   s    rv  c                 C   s   t  dd¡}|r| ¡  dS )z.Se ejecuta al destruir el application context.rq  Nrr  rt  rq   rq   rr   Úclose_db_appcontext˜   s    rw  z5--> [DEBUG] Registrando Blueprint en App Principal...z%--> [DEBUG] ID del objeto Blueprint: z:--> [DEBUG] Cantidad de rutas pendientes en el Blueprint: )Z
url_prefixÚ__main__z0.0.0.0i¸  z@Version ITGServiceManager to BluePrints Migration S01 05-03-2026z,
--- MAPA DE RUTAS CARGADAS (SIN FILTRO) ---zRuta: z | Endpoint: zTotal rutas: z,-------------------------------------------
)ÚhostÚportrw   Zuse_reloaderZthreaded)N)r<  )rŽ   rï   )rë  F)rë  F)rç  )N)N)N(Š  Ú__doc__Ú__all__r�   Útimer  rª   r°   r  r   r   r   r   Úcollectionsr   Zcentros_autodetectadosr   r	   r
   r   r   r   Zconfigurar_autodeteccionZshared_db_utilsr   Zblueprints.etiquetasr   ZrequestsZ
flask_corsr   Zdateutilr   Zflaskr   r   r   r   r   r   r   r   r   r   Zflask_jwt_extendedr   r   r   r   r    r!   r"   r#   Zwerkzeug.securityr$   r%   Zpymongor&   r'   r(   r)   r*   Zpymongo.errorsr+   Zbson.objectidr,   Zbsonr-   ZSECRET_API_PREFIXZIS_LOCALr/   r0   r1   r2   r3   Zblueprints.notificationsr4   Zblueprints.agent_datar5   Zblueprints.routes_migrationr6   Zmodules.email_senderr7   Zmodules.email_notificationsr8   r9   r:   r;   Zmodules.consolidado_estadosr<   Znanoox.nanoox_timeseriesr=   r>   r?   r@   rA   rB   Znanoox.get_datarC   Znanoox.comap_datarD   Znanoox.generate_reportrE   Z$nanoox.reports_management_ts_servicerF   Z%verificacion_status_servicios_centrosrG   ZAnalytic.Scapp_analyticsrH   rI   rJ   rK   rL   ZAnalytic.centro_idsrM   rN   rO   ZAnalytic.Scapp_feeder_scorerP   rQ   rR   rS   rT   rU   rV   Znanoox.nanoox_bolt_tsrW   rX   rY   rZ   Znanoox.generate_flux_reportr[   r¥  ZAnalytic.Scapp_notesr\   r]   r^   r_   r`   rÏ  r�   r„  rE  rÁ  rK  r  Z#HISTORIAL_CONTROL_ARRAY_LEN_TO_SENDro  rk   rC  rx   ru  r¡   rp  ZjwtZapi_bpZtoken_in_blocklist_loaderr–   Zbefore_app_requestrŸ   Zafter_requestr¦   r®   Zdirectorio_actualrm   r›   rÍ  r”  r´   r¹   r¼   r¿   rÇ   rÈ   rÉ   rÊ   r×   rå   r  r  r!  r  r   r1  r<  r>  rB  r  rC  rü   rM  rY  r[  r  rÿ   r]  ra  rh  rj  r  rq  rw  ry  r�  r�  r˜  r™  rÄ  rÐ  rÕ  rÖ  r×  rÝ  rà  rï  rñ  r‰  r   r  Zrouter  r	  r  r  r  r‹   r  r'  r)  rW  rd  rh  rn  r/  rz  r„  r‡  r˜  rŸ  r¬  r´  r¶  r¼  r¾  r¿  rÆ  rÉ  rÒ  rÕ  r×  rÚ  rß  ræ  rô  rù  rý  rþ  rÿ  r   r  r  r  r  rµ  r*  r,  r0  r3  r:  r;  r<  r=  r>  rA  rB  rC  rD  rF  rG  rI  rL  rN  rO  rM  rY  r[  r_  r`  ra  r  r?  rl  rm  rp  rq  rw  rx  rz  r~  r  r�  r�  rŽ  r�  r—  rZ  r™  r›  rš  r¢  r¤  r©  r«  r­  r¸  rJ  rº  rÃ  rÉ  rË  rÍ  rÑ  rÒ  rÓ  rß  rá  rã  rå  ræ  rì  rí  rð  rò  rô  rõ  rú  r  r  r  r  r	  r  r  r  r  r   r!  r.  r/  r)  r*  r+  r7  r;  rB  rH  rJ  r>  r?  rU  rI  rX  r\  r]  r`  rb  rc  rd  re  rf  rh  ri  rj  rk  rl  rm  rn  rp  Zteardown_requestrv  Zteardown_appcontextrw  rý  rû   Zdeferred_functionsZregister_blueprintrw   ry  rz  Zrutas_encontradasZurl_mapZ
iter_rulesZruleZendpointZapp_contextÚrunrq   rq   rq   rr   Ú<module>   sŽ   0( 	( 	$
óý










9	0N9.,	24	K7  &
"B


M#
f
 /-
[[R}KHgZ5/+3 O,DI5A.)$Y!A8*L< '20+;'PV\YEI+)'
d5#k*0_+6?);4*%&l@ 8!	
2V2U=,( 


 
