+
    iejb                         R t ^ RIt^ RIt^ RIt^ RIHtHt ^ RIHt ^ RIH	t	 ^ RI
Ht ^ RIHt ^ RIHtHtHtHtHt ^ RIHt ]P,                  ! ]4      tRtR	 R
 ltR R ltR R ltR R ltRR R lltR# )uJ  Sincronização das publicações societárias por NIF, via portal IRN.

Guarda em `dre_publications` com `source='mj'` — a tabela e a UI já existem
desde a fase da extensão Chrome, que isto substitui. As pessoas (sócios,
gerência, fiscalização) continuam a sair pelo `mj_people_parser`, que já sabia
ler exactamente este formato.

Duas decisões de custo:

* **O conteúdo só é aberto quando é preciso.** A listagem por NIF é uma chamada;
  abrir o conteúdo são três. A esmagadora maioria das publicações são prestações
  de contas, que não têm pessoas nem alteram nada — abrimos só as que ainda não
  temos e as que interessam para enriquecer a ficha.
* **Sem sweep nacional.** São 683 publicações/dia à escala do país; por NIF
  sobre as entidades monitorizadas são ~22 cada, uma vez, e depois só o novo.
N)datedatetime)Any)text)AsyncSession)MjIrnClient)capital_is_currenthtml_to_textmerge_company_fieldsparse_publicationselect_enrichment_publications)extract_peoplec                <    V ^8  d   QhR\         R\         R\         /# )   nipcpub_idreturn)str)formats   "app/services/mj_irn_sync.py__annotate__r   +   s&     F F Fc Fc F    c                 r    \         P                  ! R V  RV 2P                  4       4      P                  4       # )zmj||)hashlibsha256encode	hexdigest)r   r   s   &&r   _dedupr   +   s0    >>CvQvh/6689CCEEr   c                L    V ^8  d   QhR\         R,          R\        R,          /# )r   sNr   )r   r   )r   s   "r   r   r   /   s"      3: $+ r   c                     V '       g   R #  \         P                  ! V R,          R4      P                  4       #   \         d     R # i ; i)N:N
   Nz%Y-%m-%d)r   strptimer   
ValueError)r    s   &r   _parse_dater%   /   s?      3499;; s   +8 AAc                >    V ^8  d   QhR\         R,          R\        /# )r   actNr   )r   bool)r   s   "r   r   r   8   s     3 3d
 3t 3r   c                     T ;'       g    R P                  4       P                  4       pVP                  \        4      '       * # ) )stripupper
startswithSKIP_CONTENT_PREFIXES)r'   as   & r   _wants_contentr0   8   s2    	!!#A||1222r   c                v    V ^8  d   QhR\         R\        R\        R\        R\        \        \        3,          /# )r   sessionclient
company_idnifr   )r   r   r   dictint)r   s   "r   r   r   =   sC     a aa#.a<?aFIa	#s(^ar   c                  "   VP                  V4      G Rj  xL
 pR\        V4      R^ R^ /pV'       g   V# V P                  \        R4      RV/4      G Rj  xL
 P	                  4        Uu0 uF  pV^ ,          kK  	  pp\        V4       Uu0 uF  qR,          kK  	  p	p. p
V EF  p\        VP                  R4      4      pW9  pW9   ;'       g%    T;'       d    \        VP                  R4      4      pV'       d   VP                  V4      G Rj  xL
 MRpW9   d   V
P                  \        V4      4       V'       g   K  V'       d   \        V4      MRpT P                  \        R	4      RTR
VP                  R4      ;'       g    RR,          RT;'       g    RR,          ;'       g    RR\        VP                  R4      4      RVP                  R4      R\        P                  ! VRR7      R\!        W<4      /4      G Rj  xL
 P#                  4       pV'       g   EK  VR;;,          ^,          uu&   V^ ,          p\%        V4       F  pVP                  R4      ;'       g    RP'                  4       pV'       g   K6  T P                  \        R4      RTRTRTRVP                  R4      RVP                  R4      RVP                  R4      ;'       g    VP                  R4      ;'       g    RR\        VP                  R4      4      /4      G Rj  xL
  VR;;,          ^,          uu&   K  	  EK  	  V
'       d    \)        WV
\+        V4      R 7      G Rj  xL
  V#  ELK ELu upi u upi  EL` ELp La L5i)!z:Sincroniza um NIF. Devolve contagens para o log do scrape.NseennewpeoplezVSELECT raw_json->>'Id' FROM dre_publications WHERE company_id = :cid AND source = 'mj'cidIdAct_Facta  
                    INSERT INTO dre_publications
                        (company_id, title, summary, date, type, source, raw_json, dedup_hash)
                    VALUES (:cid, :title, :summary, :date, :type, 'mj',
                            CAST(:raw AS JSONB), :hash)
                    ON CONFLICT (dedup_hash) DO NOTHING
                    RETURNING id::text
                    titleu   Publicação:Ni  Nsummaryr*   :Ni  Nr   DatetyperawF)ensure_asciihashr5   a&  
                    INSERT INTO publication_people
                        (publication_id, company_id, person_nif, person_name, cargo, event, act_date)
                    VALUES (:pid, :cid, :nif, :name, :cargo, :event, :adate)
                    ON CONFLICT DO NOTHING
                    pidnamecargoevent	role_kindotheradate)keep_capital)publications_for_niflenexecuter   allr   r   getr0   content_forappendr   r	   r%   jsondumpsr   firstr   r+   _apply_enrichmentr   )r2   r3   r4   r5   pubsstatsrknownp
enrich_idsenrich_parsedpubr   is_newneeds_contenthtmlbodyrowpublication_idpersonnif_ps   &&&&                 r   sync_companyri   =   s@     ,,S11DSYq(A6E
 //A 
#  #%A 	
! 
  $B$#GH#GaD''#GJH*,MSWWT]#$,``1_1_N377S]K^<_0=V'',,,4  !24!89%)|D!t//	 :cggj1CC^TJ

E2::dK8CGGJ/4::c>F3/ * %'- 	. eQ$T*FZZ&,,"335E// >:5FJJv.VZZ0VZZ0VVFJJ{4KVVw[9  & (Oq O/ +S D =OPT=U
 	
 	
 L{ 2 I ->,	
s   M<M"?M<M%M<,M(>M<M-<M<"M<>M<M2-M<	M<<M<M<M<,AM<M5M< AM<'M< AM<M<1%M<M8)M<M<M:M<%M<(M<5M<8M<:M<c          
          V ^8  d   QhR\         R\        R\        \        \        \        3,          ,          R\
        RR/# )r   r2   r4   parsedrM   r   N)r   r   listr6   r   r(   )r   s   "r   r   r      sG     2 222 c3h 2 	2
 
2r   c                <  "   \        V4      pV'       g   RVR&   T P                  \        R4      RTRVP                  R4      ;'       g    RRVP                  R4      R	VP                  R	4      ;'       g    RR
VP                  R
4      RVP                  R4      RVP                  R4      RVP                  R4      RVP                  R4      RVP                  R4      RVP                  R4      R\	        VP                  R4      4      /4      G Rj  xL
  R#  L5i)u   Grava os campos do registo comercial.

`COALESCE(:campo, coluna)` em vez de sobrescrever: uma publicação que não
traga um campo não deve apagar o que já lá estava.
Ncapital_socialao  
            UPDATE companies SET
                legal_name = COALESCE(NULLIF(:firma,''), legal_name),
                natureza_juridica = COALESCE(:natureza, natureza_juridica),
                address = COALESCE(NULLIF(:sede,''), address),
                distrito = COALESCE(:distrito, distrito),
                concelho = COALESCE(:concelho, concelho),
                freguesia = COALESCE(:freguesia, freguesia),
                codigo_postal = COALESCE(:cp, codigo_postal),
                localidade = COALESCE(:localidade, localidade),
                objeto_social = COALESCE(:objeto, objeto_social),
                capital_social = COALESCE(:capital, capital_social),
                registry_complete = companies.registry_complete OR :completa,
                registry_fetched_at = now(),
                updated_at = now()
            WHERE id = :cid
            r<   firmar*   naturezanatureza_juridicasededistritoconcelho	freguesiacpcodigo_postal
localidadeobjetoobjeto_socialcapitalcompletahas_constitution)r
   rP   r   rR   r(   )r2   r4   rk   rM   fieldss   &&&& r   rX   rX      s     "&)F $( 
//	
( :VZZ(..B

#67FJJv&,,"

:.

:.K0&**_-&**\2fjj1vzz"23VZZ(:;<	
)" " "s   AD+D7BDDD)u   PRESTAÇÃO DE CONTASzPRESTACAO DE CONTAS)T)__doc__r   rU   loggingr   r   typingr   
sqlalchemyr   sqlalchemy.ext.asyncior   app.scrapers.mj_irnr   "app.services.mj_company_enrichmentr   r	   r
   r   r   app.services.mj_people_parserr   	getLogger__name__loggerr.   r   r%   r0   ri   rX    r   r   <module>r      sm        #   / +  9			8	$ I F3
aH2 2r   