
    (fi#                    n   S SK Jr   S SKJr  \" 5         S SKJrJr  S SKJrJ	r	  S SK
rS SKrS SKJr  S SKJr  S SKJrJrJr  S SKJr  S SKJr  S S	KJr  S S
KJrJ r J!r!  S SK"J#r#  S SK$J%r%  S SK&J'r'J(r(  \" SSSS9r)S.S jr*S/S jr+S0S jr,\ " S S5      5       r-\ " S S5      5       r.\)R_                  S\" \5      /SS9S 5       r0\)R_                  S\" \5      /SS9S 5       r1\)R_                  S\" \5      /SS9S 5       r2\)Rg                  S \" \5      /SS9\" S!S"S#9\" S!S$S#94   S1S% jj5       r4\)Rg                  S&\" \5      /SS9\" S'S(S#94 S2S) jj5       r5\)Rg                  S*\" \5      /SS9\" S!S"S#9\" S!S$S#94   S1S+ jj5       r6\)Rg                  S,\" \5      /SS9\" S'S(S#94 S2S- jj5       r7g)3    )annotations)load_dotenv)asdict	dataclass)IterableOptionalN)DependsFastAPIQuery)FileResponse)
get_engine)require_api_key)
QUERY_TESTQUERY_SUCURSALESQUERY_VENTAS_MINMAX)build_folios_parquet)build_lineas_parquet)
FOLIOS_DIR
LINEAS_DIRzCabanna APIz0.1.0uD   API para extracción/ETL de Cabanna y lectura eficiente de Parquets.)titleversiondescriptionc                    [         R                  " U SS9n[         R                  " U5      (       a  [        SU  35      eUR	                  5       $ )uH   Parsea YYYY-MM-DD a Timestamp (naive). Lanza ValueError si es inválido.raiseerrorsu   Fecha inválida: )pdto_datetimeisna
ValueError	normalize)sdts     ZC:\Users\julio\OneDrive\Documentos\Trabajo\Ideas Frescas\Proyectos\cabanna-api\app\main.py_parse_dater%   6   s>    	'	*B	wwr{{,QC011<<>    c              #     #    U R                  SS9nX!:  a<  Uv   U[        R                  R                  S5      -   R	                  5       nX!:  a  M;  gg7f)zT
Itera inicios de mes [start_dt, end_dt).
start_dt y end_dt se asumen normalizados.
   )dayN)replacer   offsets
MonthBeginr!   )start_dtend_dtcurs      r$   _month_rangesr0   ?   sM     
 

q

!C
,	RZZ**1--88: ,s   AAAc                6   [         R                  R                  SS9R                  S5      nUR	                  SSSSSS9nU[         R
                  R                  S5      -   nX#4SS.nU (       a*  U[         R
                  R                  S5      -
  nUnXV4US'   U$ )	zG
Retorna rangos (start,end) para:
- mes actual
- mes previo (opcional)
zAmerica/Los_Angeles)tzNr(   r   )r)   hourminutesecondmicrosecondcurrent_month
prev_monthr9   )r   	Timestampnow
tz_convertr*   r+   r,   )include_prev_monthr;   cur_inicur_finoutprev_iniprev_fins          r$   _refresh_month_windowrC   I   s     ,,

3

4
?
?
ECkkaa!kKG..q11G "+C bjj33A66%0LJr&   c                  *    \ rS rSr% S\S'   S\S'   Srg)HealthResponseb   strstatusintdb N__name__
__module____qualname____firstlineno____annotations____static_attributes__rK   r&   r$   rE   rE   b   s    KGr&   rE   c                  *    \ rS rSr% S\S'   S\S'   Srg)VentasMinMaxResponseg   zOptional[str]	fecha_min	fecha_maxrK   NrL   rK   r&   r$   rT   rT   g   s    r&   rT   z/health)dependenciesresponse_modelc                     [        5       n U R                  5        n[        R                  " [        U5      nSSS5        [        S[        WR                  S   5      S9n[        U5      $ ! , (       d  f       N9= f)z@
Verifica conectividad a DB.

Returns:
  {"status":"ok","db":1}
Nok)r   r[   )rH   rJ   )	r   connectr   read_sqlr   rE   rI   locr   )engineconndfress       r$   healthrc   n   sZ     \F		T[[T* 
 RVVG_)=
>C#;	 
	s   A**
A8z/sucursalesc                 H   [        5       n U R                  5        n[        R                  " [        U5      nSSS5        SWR
                  ;   a3  US   R                  [        5      R                  R                  5       US'   SUR                  SS90$ ! , (       d  f       Nb= f)u?   
Regresa catálogo de sucursales (NombreSucursal normalizado).
NNombreSucursalrowsrecords)orient)
r   r\   r   r]   r   columnsastyperG   stripto_dict)r_   r`   ra   s      r$   
sucursalesrm   }   s    
 \F		T[[)40 
 2::%!"23::3?CCIIKBJJiJ011 
	s   B
B!z/ventas/minmaxc                    [        5       n U R                  5        n[        R                  " [        U5      nSSS5        [        R
                  " WR                  S   SS9n[        R
                  " UR                  S   SS9n[        [        R                  " U5      (       a  SOUR                  5       [        R                  " U5      (       a  SOUR                  5       S9n[        U5      $ ! , (       d  f       N= f)z;
Regresa el rango min/max de fechas disponibles en ventas.
N)r   rV   coercer   )r   rW   )rV   rW   )r   r\   r   r]   r   r   r^   rT   r   	isoformatr   )r_   r`   ra   rV   rW   rb   s         r$   ventas_minmaxrq      s    
 \F		T[[,d3 
 rvvn5hGIrvvn5hGI
''),,$)2E2E2G''),,$)2E2E2GC #; 
	s   C..
C<z/etl/folios.zYYYY-MM-DD (inclusive))r   zYYYY-MM-DD (exclusive)c                   [        U 5      n[        U5      nX2::  a  SSS.$ [        UR                  S5      UR                  S5      SSS9n[        R                  " 5       (       a  [        [        R                  " S5      5      O/ n[        [        5      US	'   [        U5      US
'   U(       a  US   R                  OSUS'   U$ )u   
Construye parquets mensuales de folios en data/dwh/folios.

Recomendación:
- Correr por año o por rangos pequeños en entornos limitados (RAM).
errorend debe ser mayor a startrH   detail%Y-%m-%d   r(   )stop_on_consecutive_emptymin_rows_to_writezfolios_*.parquetdwh_dirparquets_nowNlast_parquet_now)
r%   r   strftimer   existssortedglobrG   lenname)startendr-   r.   resultfiless         r$   
etl_foliosr      s     5!HF!-IJJ!*%
#"#	F <F;L;L;N;NF:??#567TVEJF9 ZF>38rdFMr&   z/etl/folios/refresh_dailyTu8   También refresca el mes anterior (por ajustes tardíos)c                L   [        U 5      nUS   u  p#[        UR                  S5      UR                  S5      5        US   b1  US   u  pE[        UR                  S5      UR                  S5      5        SUR                  5        SUR                  5        3[	        U 5      S.S.$ )zA
Refresca folios del mes actual y opcionalmente el mes anterior.
r8   rw   r9   r[   z..r7   )rH   	refreshed)rC   r   r   datebool)r=   winr>   r?   rA   rB   s         r$   etl_folios_refresh_dailyr      s       2
3C?+G))*5w7G7G
7ST
<$ .X..z:H<M<Mj<YZ  '/r',,.1AB12
 r&   z/etl/lineasc                    [        U 5      n[        U5      nX2::  a  SSS.$ [        UR                  S5      UR                  S5      5        SXS.$ )u=   
Construye parquets mensuales de líneas en data/dwh/lineas.
rs   rt   ru   rw   r[   )rH   r   r   )r%   r   r   )r   r   r-   r.   s       r$   
etl_lineasr      sS     5!HF!-IJJ**:6
8STU77r&   z/etl/lineas/refresh_dailyc                    [        U 5      nUS   u  p#[        UR                  S5      UR                  S5      5      nS nUS   b1  US   u  pg[        UR                  S5      UR                  S5      5      nSUUS.$ )Nr8   rw   r9   r[   )rH   r8   r9   )rC   r   r   )r=   r   r>   r?   r1r2rA   rB   s           r$   etl_lineas_refresh_dailyr      s       2
3C?+G	g..z:G<L<LZ<X	YB	B
<$ .!("3"3J"?ARARS]A^_  r&   )r"   rG   returnpd.Timestamp)r-   r   r.   r   r   zIterable[pd.Timestamp])r=   r   r   dict)r   rG   r   rG   )r=   r   )8
__future__r   dotenvr   dataclassesr   r   typingr   r   pandasr   pyarrowpapyarrow.datasetdatasetdspyarrow.parquetparquetpqfastapir	   r
   r   fastapi.responsesr   app.dbr   app.securityr   app.queriesr   r   r   app.dwh.etl_foliosr   app.dwh.etl_lineasr   app.dwh.pathsr   r   appr%   r0   rC   rE   rT   getrc   rm   rq   postr   r   r   r   rK   r&   r$   <module>r      sL   "*   ) %     + + *  ( I I 3 3 0 
V;2       '/":!;DQ R go&>%?PTU2 V2 	)A(BSWX Y( -w'?&@QUVs(@AS&>?	 W> 
%W_5M4N_cd$T7qr e4 -w'?&@QUVs(@AS&>?88	8 W8 
%W_5M4N_cd$T7qr er&   