+
    [ej                     x   R t ^ RIt^ RIHtHt ^ RIHtHtH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 ^ R
IHt ]P0                  ! ]4      t]! RR.R7      t ! R R]
4      t ! R R]
4      t ! R R]
4      tR R lt]PA                  R]R7      ]PB                  ! R4      R R l4       4       t"R# )u  Watchlist de insolvências (v1 public API).

Alimentada pelo Sabichão: ao criar um cliente, o NIF é empurrado para cá e a
entidade passa a ser vigiada nos anúncios de insolvência do CITIUS.

Duas garantias que moldam o desenho:

* **Nunca se remove.** Um cliente desactivado continua a ser um devedor cujo
  processo de insolvência interessa acompanhar. O endpoint só faz upsert.
* **Idempotente e tolerante.** O Sabichão chama isto no fluxo de criação de
  cliente; se falhar, o cliente tem de ser criado na mesma. Do lado de cá isso
  traduz-se em aceitar repetições sem erro e em normalizar o NIF (o Sabichão
  guarda-os com espaços, "517 607 891").
N)	AnnotatedAny)	APIRouterDependsRequest)	BaseModelField)text)AsyncSession)require_api_key)get_session)limiter)rematch_nifz
/watchlistz
public-api)prefixtagsc                   V   a  ] tR t^!t o ]! RR7      tRt]! RRR7      tV 3R ltRt	V t
R# )WatchlistItemu'   NIF/NIPC; aceita espaços e pontuaçãodescriptionNu2   Referência do sistema de origem (nº de contrato))defaultr   c                Z   < V ^8  d   Qh/ S[ ;R&   S[ R,          ;R&   S[ R,          ;R&   # )   nifNnameexternal_refstr)format__classdict__s   "app/api/v1/watchlist.py__annotate__WatchlistItem.__annotate__!   s2     	K 
*  *       )__name__
__module____qualname____firstlineno__r   r   r   r   __annotate_func____static_attributes____classdictcell__r   s   @r   r   r   !   s,     !JKCD$"V L  r"   r   c                   ,   a  ] tR t^)t o V 3R ltRtV tR# )WatchlistSyncc                6   < V ^8  d   Qh/ S[ S[,          ;R&   # )r   items)listr   )r   r   s   "r   r    WatchlistSync.__annotate__)   s      r"   r#   N)r$   r%   r&   r'   r(   r)   r*   r+   s   @r   r-   r-   )   s      r"   r-   c                   P   a  ] tR t^-t o ]! RR7      t]! RR7      tV 3R ltRtV t	R# )WatchlistResultu)   NIFs rejeitados por não terem 9 dígitosr   u@   Anúncios já arquivados que passaram a dar match com estes NIFsc                Z   < V ^8  d   Qh/ S[ ;R&   S[ ;R&   S[S[,          ;R&   S[ ;R&   # )r   	recebidosaceites	ignoradoshits_retroactivos)intr0   r   )r   r   s   "r   r    WatchlistResult.__annotate__-   s9     N L  CyY   	 r"   r#   N)
r$   r%   r&   r'   r   r7   r8   r(   r)   r*   r+   s   @r   r3   r3   -   s'      !-XYI"V	  r"   r3   c                L    V ^8  d   QhR\         R,          R\         R,          /# )r   rawNreturnr   )r   s   "r   r    r    6   s"     0 03: 0#* 0r"   c                 n    V '       g   R # RP                  R V  4       4      p\        V4      ^	8X  d   V# R # )N c              3   T   "   T F  qP                  4       '       g   K  Vx  K   	  R # 5i)N)isdigit).0chs   & r   	<genexpr>_norm_nif.<locals>.<genexpr>9   s     6#BRR#s   (
()joinlen)r<   digitss   & r   	_norm_nifrI   6   s2    WW6#66F[A%6/4/r"   r?   )response_modelz	60/minutec                    V ^8  d   QhR\         R\        R\        \        \	        \
        4      3,          R\        \        \        \        3,          \	        \        4      3,          R\        /# )r   requestpayloadsessionkeyr=   )r   r-   r   r
   r   r   dictr   r   r   r3   )r   s   "r   r    r    ?   s`     = === |W[%99:= 
4S>7?#;;	<	=
 =r"   c           
       "   ^ p. p^ pVP                    F  p\        VP                  4      pV'       g   VP                  VP                  4       K=  VP	                  \        R4      RVRVP                  RVP                  /4      G Rj  xL
  TP	                  \        R4      RTRVP                  ;'       g    RV 2/4      G Rj  xL
  T\        W(4      G Rj  xL
 ,          pV^,          pK  	  VP                  4       G Rj  xL
  \        P                  RVP                  R	4      V\        V4      V4       \        \        VP                   4      VVVR
7      #  L L L L]5i)u$  Regista (ou actualiza) entidades a vigiar. Aceita um ou muitos.

Cada NIF novo é imediatamente cruzado contra **todo** o arquivo de anúncios
já guardado — é o que dá sentido a varrer o país inteiro: um cliente
adicionado hoje pode já ter sido declarado insolvente na semana passada.
a  
                INSERT INTO insolvency_watchlist (nif, name, source, external_ref)
                VALUES (:nif, :name, 'sabichao', :ref)
                ON CONFLICT (nif) DO UPDATE SET
                    name = COALESCE(EXCLUDED.name, insolvency_watchlist.name),
                    external_ref = COALESCE(
                        EXCLUDED.external_ref, insolvency_watchlist.external_ref),
                    active = true,
                    updated_at = now()
                r   r   refNz
                INSERT INTO companies (nif, legal_name, monitoring_type, monitored)
                VALUES (:nif, :name, 'client', true)
                ON CONFLICT (nif) DO NOTHING
                zNIF zGwatchlist sync (key=%s): %d aceites, %d ignorados, %d hits retroactivoslabel)r5   r6   r7   r8   )r/   rI   r   appendexecuter	   r   r   r   commitloggerinfogetrG   r3   )	rL   rM   rN   rO   r6   r7   hitsitemr   s	   &&&&     r   sync_watchlistr\   =   s]     GID!TXX&oo	 CE43D3DE
 	
 	
" oo C!:!:SEl;	
 		
 		
 	k'///1C F ..

KKQ'3y>4 gmm$	 G	
"		
 0 sO   BE'
E.E':E'E!	E'E#*E'E%AE'!E'#E'%E')#__doc__loggingtypingr   r   fastapir   r   r   pydanticr   r   
sqlalchemyr	   sqlalchemy.ext.asyncior
   app.auth.api_key_authr   app.dbr   app.rate_limitr    app.services.insolvency_matchingr   	getLoggerr$   rW   routerr   r-   r3   rI   postlimitr\   r#   r"   r   <module>rl      s     ! / / %  / 1  " 8			8	$	,l^	<I I i 0 R0{=  1=r"   