Ë
    !¬jÙ*  ã                   ó*  — d 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Zddl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Zd	Zd
ZdZdZdeddfd„Z ee«        ej4                  dd«      j7                  «       Z ej4                  dd«      j7                  «       Zeres1ej<                  j?                  de› d�«        ej@                  d«       de› �dddœZ! ee«      jD                  jG                  dd¬«        ejH                  d«      Z%e%jM                  ejN                  «       de%_(        e%jR                  sŽ eeddd ¬!«      Z*e*jW                   ejX                  d"d#«      «       e%j[                  e*«        ej\                  ej^                  «      Z0e0jW                   ejX                  d"d#«      «       e%j[                  e0«       d9d$ed%eddfd&„Z1dejd                  fd'„Z3 e3«       Z4dejj                  fd(„Z6d)ejj                  d*ededz  fd+„Z7d)ejj                  d*ed,eddfd-„Z8de9e:   fd.„Z;d/ede<ee9e:   f   fd0„Z=d1e9e:   defd2„Z>d*ed,ede?fd3„Z@d)ejj                  d4e:d5e:ddfd6„ZAdeBfd7„ZCeDd8k(  r ej@                   eC«       «       yy):u  
Atualiza o campo 'Status Tarefa' nas oportunidades do pipeline PX3.
ðŸŸ¢ = tem tarefa futura (em dia)
ðŸŸ¡ = sem tarefa cadastrada
ðŸ”´ = tem tarefa vencida (atrasada)
Roda via cron a cada 30 minutos (com flock).

Melhorias 2026-09-15:
- Credenciais em /opt/mia/config/farois_px3.env (chmod 600)
- Distingue "sem tarefa" de "falha de leitura" (nÃ£o pinta ðŸŸ¡ falso)
- Cache SQLite local para pular PUTs redundantes
- requests.Session com Retry/backoff (429/5xx + Retry-After)
- Log rotacionado (10MB x 3 backups) + duraÃ§Ã£o da execuÃ§Ã£o
é    N)ÚdatetimeÚtimezone)ÚRotatingFileHandler)ÚPath)ÚHTTPAdapter)ÚRetryz/opt/mia/config/linkia_px3.envz/opt/mia/data/farois_px3.dbz!/opt/mia/logs/farois_pipeline.logz$https://services.leadconnectorhq.comÚcvrJJ7rlAuIGgCL42NEHÚpathÚreturnc                 óÐ  — t         j                  j                  | «      syt        | dd¬«      5 }|D ]�  }|j	                  «       }|r|j                  d«      sd|vrŒ+|j                  d«      \  }}}|j	                  «       }|j	                  «       j	                  d«      j	                  d«      }t         j                  j                  ||«       ŒŸ 	 ddd«       y# 1 sw Y   yxY w)	uL   Carrega KEY=VALUE do arquivo pra os.environ (dotenv-like, sem dependÃªncia).NÚrúutf-8)Úencodingú#ú=ú"ú')	Úosr
   ÚisfileÚopenÚstripÚ
startswithÚ	partitionÚenvironÚ
setdefault)r
   ÚfÚrawÚlineÚkeyÚ_Úvals          ú5/opt/mia/workspace/clientes/px3lab/farois_pipeline.pyÚ	_load_envr#   ,   s½   € ä�7‰7�>‰>˜$ÔØÜ	ˆd�C 'Ô	*ð ,¨aØò 	,ˆCØ—9‘9“;ˆDÙ˜4Ÿ?™?¨3Ô/°3¸d±?ØØŸ.™.¨Ó-‰KˆC��CØ—)‘)“+ˆCØ—)‘)“+×#Ñ# CÓ(×.Ñ.¨sÓ3ˆCÜ�J‰J×!Ñ! # sÕ+ñ	,÷,÷ ,ñ ,ús   ¯B#CÃC%Ú	GHL_TOKENÚ ÚGHL_LOCATIONz3[FATAL] GHL_TOKEN/GHL_LOCATION ausentes. Verifique ú
é   zBearer z
2021-07-28zapplication/json)ÚAuthorizationÚVersionzContent-TypeT©ÚparentsÚexist_okÚ
farois_px3Fi    é   r   )ÚmaxBytesÚbackupCountr   z%%(asctime)s %(levelname)s %(message)sz%Y-%m-%d %H:%M:%SÚmsgÚlevelc                 ój   —  t        t        |j                  «       t        j                  «      | «       y )N)ÚgetattrÚloggerÚlowerÚinfo)r2   r3   s     r"   Úlogr9   e   s   € Ø/„GŒF�E—K‘K“M¤6§;¡;Ó/°Õ4ó    c                  ó  — t        j                  «       } t        ddddddt        g d¢«      dd¬«	      }t	        |dd¬	«      }| j                  d
|«       | j                  d|«       | j                  j                  t        «       | S )Nr/   g      ð?)i­  iô  iö  i÷  iø  )ÚGETÚPUTÚPOSTTF)	ÚtotalÚconnectÚreadÚstatusÚbackoff_factorÚstatus_forcelistÚallowed_methodsÚrespect_retry_after_headerÚraise_on_statusé    )Úmax_retriesÚpool_connectionsÚpool_maxsizezhttps://zhttp://)	ÚrequestsÚSessionr   Ú	frozensetr   ÚmountÚheadersÚupdateÚHEADERS)ÚsÚretryÚadapters      r"   Ú_build_sessionrV   m   s~   € Ü×ÑÓ€AÜØØØØØØ2Ü!Ò"8Ó9Ø#'Øô
€Eô  e¸bÈrÔR€GØ‡G�GˆJ˜Ô Ø‡G�GˆI�wÔØ‡I�I×Ñ”WÔØ€Hr:   c                  óô   — t        t        «      j                  j                  dd¬«       t	        j
                  t        d¬«      } | j                  d«       | j                  d«       | j                  «        | S )NTr+   é
   ©Útimeoutz°
        CREATE TABLE IF NOT EXISTS farois_cache (
            opp_id TEXT PRIMARY KEY,
            farol TEXT NOT NULL,
            updated_at TEXT NOT NULL
        )
        zPCREATE INDEX IF NOT EXISTS idx_farois_cache_updated ON farois_cache (updated_at))r   ÚDB_PATHÚparentÚmkdirÚsqlite3r@   ÚexecuteÚcommit)Úconns    r"   Ú_cache_connrb   ˆ   sa   € ÜŒƒM×Ñ×Ñ t°dÐÔ;Ü�?‰?œ7¨BÔ/€DØ‡L�Lð	ôð 	‡L�LØZôð 	‡K�K„MØ€Kr:   ra   Úopp_idc                 óV   — | j                  d|f«      j                  «       }|r|d   S d S )Nz/SELECT farol FROM farois_cache WHERE opp_id = ?r   )r_   Úfetchone)ra   rc   Úrows      r"   Ú	cache_getrg   ›   s/   € Ø
�,‰,ÐHÈ6È)Ó
T×
]Ñ
]Ó
_€CÙˆ3ˆq‰6Ð"˜dÐ"r:   Úfarolc                 óŒ   — | j                  d||t        j                  t        j                  «      j                  «       f«       y )Nz¾
        INSERT INTO farois_cache (opp_id, farol, updated_at)
        VALUES (?, ?, ?)
        ON CONFLICT(opp_id) DO UPDATE SET farol=excluded.farol, updated_at=excluded.updated_at
        )r_   r   Únowr   ÚutcÚ	isoformat)ra   rc   rh   s      r"   Ú	cache_setrm       s5   € Ø‡L�Lð	ð
 
�œŸ™¤X§\¡\Ó2×<Ñ<Ó>Ð?õr:   c                  óJ  — g } t         dddœ}	 	 t        j                  t        › d�|d¬«      }|j                  d
k7  r,t        d|j                  › d|j                  d	d
 › �d«       	 | S |j                  «       }|j                  d«      xs g }| j                  |«       |j                  di «      }|j                  d«      }|j                  d«      }|r|rt        |«      dk  r	 | S t         dd||dœ}Œç# t        j
                  $ r}t        d|›�d«       Y d	}~| S d	}~ww xY w)uL   Busca todas as oportunidades abertas da location (paginaÃ§Ã£o cursor-based).r   éd   )Úlocation_idrB   Úlimitz/opportunities/searché   )ÚparamsrZ   u    buscar_oportunidades: exceÃ§Ã£o ÚERRORNéÈ   zbuscar_oportunidades: HTTP ú - ÚopportunitiesÚmetaÚ
startAfterÚstartAfterId)rp   rB   rq   ry   rz   )r&   ÚSESSIONÚgetÚGHL_BASErL   ÚRequestExceptionr9   Ústatus_codeÚtextÚjsonÚextendÚlen)	Úoppsrs   r   ÚeÚdataÚbatchrx   Ústart_afterÚstart_after_ids	            r"   Úbuscar_oportunidadesrŠ   ¯   s:  € à€DÜ)°VÀcÑJ€FØ
ð	Ü—‘œx˜jÐ(=Ð>ÀvÐWY�ÓZˆAð �=‰=˜CÒÜÐ-¨a¯m©m¨_¸CÀÇÁÀtÈÀ¸~ÐNÐPWÔXØð  €Kð �v‰v‹xˆØ—‘˜Ó)Ò/¨RˆØ�‰�EÔØ�x‰x˜ Ó#ˆØ—h‘h˜|Ó,ˆØŸ™ .Ó1ˆÙ¡.´C¸³JÀÒ4DØð €Kô (ØØØ%Ø*ñ
ˆð# øô ×(Ñ(ò 	ÜÐ2°1°%Ð8¸'ÔBÛð& €Kûð+	ús   �C5 Ã5D"ÄDÄD"Ú
contact_idc           
      óø  — 	 t         j                  t        › d| › d�d¬«      }|j                  d
k(  rdg fS |j                  dk7  r0t        d| › d|j                  › d|j                  d	d › �d«       dg fS 	 |j                  «       j                  d«      xs g }|rd|fS d|fS # t        j                  $ r }t        d| › d|›�d«       dg fcY d	}~S d	}~ww xY w# t        $ r t        d| › d�d«       dg fcY S w xY w)uý   
    Retorna (status, tarefas):
      - ("ok",   [...])  -> leitura bem-sucedida com N tarefas
      - ("empty", [])    -> leitura bem-sucedida, sem tarefas
      - ("fail", [])     -> falha de leitura (timeout, 429 pÃ³s-retry, 5xx, 4xx inesperado)
    z
/contacts/z/tasksé   rY   zbuscar_tarefas_contato(õ   ): exceÃ§Ã£o ÚWARNINGÚfailNi”  Úemptyru   ú): HTTP rv   Útasksu   ): JSON invÃ¡lidoÚok)
r{   r|   r}   rL   r~   r9   r   r€   r�   Ú
ValueError)r‹   r   r…   Útarefass       r"   Úbuscar_tarefas_contator—   Î   s'  € ðÜ�K‰Kœ8˜* J¨z¨l¸&ÐAÈ2ˆKÓNˆð
 	‡}�}˜Òà˜ˆ}ÐØ‡}�}˜ÒÜØ% j \°¸!¿-¹-¸ÈÈAÏFÉFÐSWÐTWÈLÈ>ÐZØô	
ð ˜ˆ|ÐðØ—&‘&“(—,‘,˜wÓ'Ò-¨2ˆñ
 ˆD¨'Ð2Ð2 ¨'Ð2Ð2øô) ×$Ñ$ò ÜÐ% j \°¸q¸eÐDÀiÔPØ˜ˆ|Õûðûô  ò ÜÐ% j \Ð1BÐCÀYÔOØ˜ˆ|Òðús/   ‚!B# Á6#C Â#CÂ6CÃCÃCÃC9Ã8C9r–   c                 óÚ  — | D �cg c]  }|j                  d«      rŒ|‘Œ }}|syt        j                  t        j                  «      }|D ]‹  }|j                  d«      }|sŒ	 t        |t        t        f«      r)t        j                  |dz  t        j                  ¬«      }n.t        j                  t        |«      j                  dd«      «      }||k  r yŒ� y	c c}w # t        $ r Y ŒŸw xY w)
NÚ	completedu   ðŸŸ¡ÚdueDateiè  )ÚtzÚZz+00:00u   ðŸ”´u   ðŸŸ¢)r|   r   rj   r   rk   Ú
isinstanceÚintÚfloatÚfromtimestampÚfromisoformatÚstrÚreplaceÚ	Exception)r–   ÚtÚ	pendentesÚagoraÚdueÚdts         r"   Úcalcular_farolrª   î   sÖ   € Ø#Ö>�q¨1¯5©5°Õ+=’Ð>€IÐ>ÙØÜ�L‰LœŸ™Ó&€EØò ˆØ�e‰e�IÓˆÙØð	Ü˜#¤¤U˜|Ô,Ü×+Ñ+¨C°$©J¼8¿<¹<ÔH‘ä×+Ñ+¬C°«H×,<Ñ,<¸SÀ(Ó,KÓL�Ø�EŠzÙð ðð ùò# ?øô ò 	Ùð	ús   …CœCÁ"A2CÃ	C*Ã)C*c           
      ó:  — dt         |dœgi}	 t        j                  t        › d| › �|d¬«      }|j                  d
v ryt        d| › d|j                  › d|j                  d d › �d«       y	# t        j
                  $ r}t        d| › d|›�d«       Y d }~y	d }~ww xY w)NÚcustomFields)ÚidÚvaluez/opportunities/r�   )r�   rZ   zatualizar_oportunidade(rŽ   r�   F)ru   éÉ   Tr’   rv   ru   )	ÚCAMPO_STATUS_IDr{   Úputr}   rL   r~   r9   r   r€   )rc   rh   Úbodyr   r…   s        r"   Úatualizar_oportunidader³     s±   € Ø¤O¸eÑDÐEÐF€DðÜ�K‰Kœ8˜* O°F°8Ð<À4ÐQSˆKÓTˆð 	‡}�}˜
Ñ"ØÜØ
! & ¨°!·-±-°ÀÀAÇFÁFÈ4ÈCÀLÀ>ÐRØôð øô ×$Ñ$ò ÜÐ% f X¨]¸1¸%Ð@À)ÔLÜûðús   Ž!A+ Á+BÁ>BÂBÚoppÚcountersc                 ó¶  — |j                  d«      }|j                  d«      xs$ |j                  d«      xs i j                  d«      }|r|s|dxx   dz  cc<   y t        |«      \  }}|dk(  r|dxx   dz  cc<   y t        |«      }t        | |«      }||k(  r|dxx   dz  cc<   y t	        ||«      rt        | ||«       |d	xx   dz  cc<   y |d
xx   dz  cc<   y )Nr­   Ú	contactIdÚcontactÚpuladas_sem_idé   r�   Úfalhas_leituraÚinalteradosÚatualizadosÚfalhas_escrita)r|   r—   rª   rg   r³   rm   )	ra   r´   rµ   rc   r‹   rB   r–   rh   Úanteriors	            r"   Úprocessar_oportunidaderÀ     sæ   € Ø�W‰W�T‹]€FØ—‘˜Ó%ÒM¨#¯'©'°)Ó*<Ò*BÀ×)GÑ)GÈÓ)M€JÙ™ØÐ!Ó" aÑ'Ó"Øä,¨ZÓ8�O€FˆGØ�ÒØÐ!Ó" aÑ'Ó"Øä˜7Ó#€EÜ˜˜vÓ&€HØ�5ÒØ�Ó 1Ñ$ÓØä˜f eÔ,Ü�$˜ Ô&Ø�Ó 1Ñ$ÔàÐ!Ó" aÑ'Ô"r:   c                  óÄ  — t        j                  «       } t        d«       t        «       }t        dt	        |«      › �«       t        «       }ddddddœ}	 |D ]  }t        |||«       Œ |j                  «        |j                  «        t        j                  «       | z
  }t        d|d   › d|d   › d	|d
   › d|d   › d|d   › d|d›�«       y# |j                  «        w xY w)Nu&   iniciando atualizaÃ§Ã£o de farÃ³is PX3zoportunidades encontradas: r   )r½   r¼   r»   r¾   r¹   zresumo: atualizados=r½   z | inalterados=r¼   z | falhas_leitura=r»   z | falhas_escrita=r¾   z | puladas_sem_id=r¹   z | duracao_segundos=z.1f)	ÚtimeÚ	monotonicr9   rŠ   rƒ   rb   rÀ   r`   Úclose)Ústartr„   ra   rµ   r´   Úduracaos         r"   ÚmainrÇ   0  s  € Ü�N‰NÓ€EÜÐ0Ô1äÓ!€DÜÐ
%¤c¨$£i [Ð1Ô2ä‹=€DàØØØØñ€HðØò 	8ˆCÜ" 4¨¨hÕ7ð	8à�‰Œà�
‰
Œä�n‰nÓ Ñ&€GÜð	Ø Ñ.Ð/ð 0Ø Ñ.Ð/ð 0Ø"Ð#3Ñ4Ð5ð 6Ø"Ð#3Ñ4Ð5ð 6Ø"Ð#3Ñ4Ð5ð 6Ø# C˜=ð	*ôð øð 	�
‰
�ús   Á$C ÃCÚ__main__)ÚINFO)EÚ__doc__r�   Úloggingr   Úrandomr^   ÚsysrÂ   r   r   Úlogging.handlersr   Úpathlibr   rL   Úrequests.adaptersr   Úurllib3.util.retryr   ÚENV_FILEr[   ÚLOG_PATHr}   r°   r¢   r#   Úgetenvr   r$   r&   ÚstderrÚwriteÚexitrR   r\   r]   Ú	getLoggerr6   ÚsetLevelrÉ   Ú	propagateÚhandlersÚhandlerÚsetFormatterÚ	FormatterÚ
addHandlerÚStreamHandlerÚstdoutÚstreamr9   rM   rV   r{   Ú
Connectionrb   rg   rm   ÚlistÚdictrŠ   Útupler—   rª   Úboolr³   rÀ   rž   rÇ   Ú__name__© r:   r"   ú<module>rê      s  ðñó Û Û 	Û Û Û 
Û ß 'Ý 0Ý ã Ý )Ý $ð ,€Ø
'€Ø.€à1€Ø(€ð,�Cð ,˜Dó ,ñ 
ˆ(Ô àˆB�I‰I�k 2Ó&×,Ñ,Ó.€	Øˆr�y‰y˜¨Ó,×2Ñ2Ó4€á™Ø‡J�J×ÑØ
=¸h¸ZÀrÐJôð €C‡H�HˆQ„Kð ˜y˜kÐ*ØØ&ñ€ñ €Xƒ× Ñ × Ñ  D°4Ð Ô 8à	ˆ×	Ñ	˜<Ó	(€Ø ‡��—‘Ô Ø€Ô Ø‡‚Ù!ØÐ+¸ÀWô€Gð ×ÑØˆ×ÑÐAÐCVÓWôð ×Ñ�gÔà"ˆW×"Ñ" 3§:¡:Ó.€FØ
×ÑØˆ×ÑÐAÐCVÓWôð ×Ñ�fÔñ5ˆSð 5˜ð 5¨$ó 5ð˜×(Ñ(ó ñ( Ó
€ð�W×'Ñ'ó ð&#�G×&Ñ&ð #°ð #¸¸d¹
ó #ð
�G×&Ñ&ð °ð ¸Cð ÀDó ð˜d 4™jó ð>3 sð 3¨u°S¸$¸t¹*°_Ñ/Eó 3ð@˜D ™Jð ¨3ó ð* 3ð ¨sð °tó ð(( ×!3Ñ!3ð (¸$ð (È$ð (ÐSWó (ð2!ˆcó !ðH ˆzÒØ€C‡H�H‰T‹VÕð r:   