
    ]Eh8C                         d dl mZmZmZmZ d dlmZ d dlmZ d dlm	Z	 d dl
Z
d dlZd dlmZmZmZmZ d dlmZ e G d d	             Ze G d
 d             Z G d d      Zy)    )	EerrModelExpenseTypeModelBranchOfficeModelRemunerationModel)AuthenticationClass)datetime
monthrangeN)DictListTupleOptional)	dataclassc                   D    e Zd ZU dZeed<   dZee   ed<   dZ	ee
   ed<   y)	ApiResultz$Estructura para resultados de la APIsuccessNdataerror)__name__
__module____qualname____doc__bool__annotations__r   r   r   r   str     J/var/www/intrajisbackend.com/public_html/app/backend/classes/seat_class.pyr   r   
   s&    .MD(4.E8C=r   r   c                   J    e Zd ZU dZdZeed<   dZeed<   dZeed<   dZ	eed<   y)ProcessingStatsu   Estadísticas de procesamientor   processed_seatsprocessed_detailsprocessed_remunerationsskipped_recordsN)
r   r   r   r   r!   intr   r"   r#   r$   r   r   r   r    r       s/    (OSs#$S$OSr   r    c                   X   e Zd ZdZdZdZdZd Zdedede	e
e
e
f   fd	Zd
e
ddfdZdee
e
f   fdZde
de
dee
e
f   fdZde
de
de
de
def
dZde
de
fdZdee
   dee   fdZdedee   de
defdZdeded
e
de	eef   fdZdee   d
e
defd Zd
e
defd!Zd"e
de
de
dededefd#Zy)$	SeatClassz'Clase para manejo de asientos contablesz8https://libredte.cl/api/lce/lce_asientos/buscar/76063822 JXou3uyrc7sNnP2ewOCX38tWZ6BTm4D1Bancoc                 2    || _         t        |      | _        y N)dbr   
auth_class)selfr,   s     r   __init__zSeatClass.__init__!   s    -b1r   monthyearreturnc                 f    t        ||      d   }|d}| d| d}| d| d|d}| d| }|||fS )u  
        Obtiene información del período: fechas de inicio, fin y período formateado
        
        Args:
            month: Mes (1-12)
            year: Año
            
        Returns:
            Tupla con (fecha_desde, fecha_hasta, período_formateado)
           02d-z-01r	   )r.   r0   r1   days_in_month	month_strsinceuntilperiods           r   get_period_infozSeatClass.get_period_info%   sf     #4/2Sk	&)C(&)AmC%8969+&eV##r   r;   Nc                 z   	 | j                   j                  t              j                  t        j                  |k(        j                         }| j                   j                          t        d| d|        y# t        $ r6}| j                   j                          t        dt        |             d}~ww xY w)u~   
        Elimina datos existentes del período
        
        Args:
            period: Período en formato YYYY-MM
        zEliminados u#    registros existentes del período z#Error al limpiar datos existentes: N)r,   queryr   filterr;   deletecommitprint	Exceptionrollbackr   )r.   r;   deleted_countes       r   clear_existing_datazSeatClass.clear_existing_data:   s    	L GGMM)4;;  F*fh  GGNNK.QRXQYZ[ 	LGGA#a&JKK	Ls   A8A; ;	B:1B55B:c                 &    d| j                    ddS )z'Obtiene headers para la API de LibreDTEzBearer zapplication/json)AuthorizationzContent-Type)LIBREDTE_TOKEN)r.   s    r   get_api_headerszSeatClass.get_api_headersK   s"      't':':&;<.
 	
r   r9   r:   c                      d||ddddddddddS )z,Construye el payload para la API de LibreDTE )periodofecha_desdefecha_hastaglosa	operacioncuentadebe
debe_desde
debe_hastahaberhaber_desdehaber_hastar   )r.   r9   r:   s      r   build_api_payloadzSeatClass.build_api_payloadR   s2       
 	
r   rutpasswordc                    	 | j                  ||      }| j                         }t        j                  | j                  ||d      }|j
                  dk(  sd|j                  j                         v rJt        d       | j                  j                  ||       t        j                  | j                  ||d      }|j
                  dk(  rt        d|j                               S t        d	d
|j
                   d|j                         S # t        j                  $ r#}t        d	dt        |             cY d}~S d}~wt        $ r#}t        d	dt        |             cY d}~S d}~ww xY w)aH  
        Obtiene datos de la API externa de LibreDTE
        
        Args:
            since: Fecha desde
            until: Fecha hasta
            rut: RUT para renovar token si es necesario
            password: Password para renovar token
            
        Returns:
            ApiResult con los datos obtenidos
           )jsonheaderstimeouti  ztoken-invalidou5   Token LibreDTE inválido, renovando external_token...   T)r   r   FzError HTTP : r   r   u   Error de conexión: NzError inesperado: )rZ   rK   requestspostLIBREDTE_API_URLstatus_codetextlowerrB   r-   create_external_tokenr   r_   RequestExceptionr   rC   )	r.   r9   r:   r[   r\   payloadr`   responserF   s	            r   fetch_external_datazSeatClass.fetch_external_datac   sP   #	Q,,UE:G**,G}}%%	H ##s*.>(--BUBUBW.WMN55c8D $==)) #	 ##s* HMMODD !'(<(<'=RO 
 (( 	SU4HQ2QRR 	QU4Fs1vh2OPP	Qs6   C#D &&D E- D>8E->E-
E("E-(E-ri   c                 r    |syddl }|j                  dd|j                               j                         }|S )u7   Normaliza texto eliminando puntuación y espacios extrarM   r   Nz[.,\s]+ )resubrj   strip)r.   ri   rr   
normalizeds       r   normalize_textzSeatClass.normalize_text   s2    VVJTZZ\:@@B
r   description_partsc           	        
 |sy|d   }| j                  |      }t        d| d| d       | j                  j                  t              j                  t        j                  |k(        j                         }|rt        d|j                          |S | j                  j                  t              j                         }|D ]  }|j                  s| j                  |j                        }||k(  rt        d|j                          |c S |j                         }|j                         
t        |      dk\  s{t        
fd	|D              }	|	t        |      d
z  k\  st        d|	 dt        |       d|j                          |c S  |D ]H  }|j                  s|| j                  |j                        v s.t        d|j                          |c S  t        d| d       y)u  
        Encuentra la sucursal basada en la descripción usando coincidencias flexibles
        
        Args:
            description_parts: Partes de la descripción dividida por '_'
            
        Returns:
            BranchOfficeModel encontrado o None
        Nr   zBuscando sucursal para: 'z' (normalizado: 'z')z$Encontrado con coincidencia exacta: z)Encontrado con coincidencia normalizada:    c              3   N   K   | ]  t        fd D              sd  yw)c              3   &   K   | ]  }|v  
 y wr+   r   ).0bo_wordwords     r   	<genexpr>z9SeatClass.find_branch_office.<locals>.<genexpr>.<genexpr>   s     ?hT[?hs   r4   N)any)r|   r~   bo_wordss    @r   r   z/SeatClass.find_branch_office.<locals>.<genexpr>   s     iDC?h_g?h<hais   %%g?z%Encontrado con coincidencia parcial (/z palabras): zEncontrado con LIKE: u    No se encontró sucursal para: '')rv   rB   r,   r>   r   r?   branch_officefirstallsplitlensum)r.   rw   search_termsearch_normalizedr   branch_officesbobo_normalizedsearch_wordsmatchesr   s             @r   find_branch_officezSeatClass.find_branch_office   s    !'* //<)+6GHYGZZ\]^ &78??++{:

%' 	 89T9T8UVW   '89==?  	B## //0@0@AM !M1A"BRBRASTU	 -224L$**,H< A%iLiic,/#55A'!CP\L]K^^jkmk{k{j|}~I)	. ! 	B## D$7$78H8H$II-b.>.>-?@A		 	0Q?@r   detail_itemexpense_typedetail_descriptionc                    |j                  dd      }|j                  dd      }|rt        |      }n|rt        |      }ny|rt        |d      r|j                  s|S |j                  }d|v rd|v r||z  |z  dz  S |dz  S ||z  S )	uP  
        Calcula el monto final considerando debe/haber y positive_negative_id
        
        Args:
            detail_item: Item de detalle de la API
            expense_type: Tipo de gasto encontrado
            detail_description: Descripción completa del detalle
            
        Returns:
            Monto calculado
        rT   rM   rW   g        positive_negative_idNotaCreditoNotaCreditoCompra)getfloathasattrr   )r.   r   r   r   rT   rW   base_amount
multipliers           r   calculate_amountzSeatClass.calculate_amount   s     vr*, +K,K 7<9O#PXdXyXy!66
 .."&88"Z/*<rAA #R'' ++r   	seat_datar   c                    d}d}|j                  dd      }|j                  dd      }|j                  dg       D ]  }	 |j                  d      | j                  k(  r|dz  })|j                  dd      }	| j                  j                  t              j                  t        j                  |	k(        j                         }
| j                  ||
|      }t        |j                  |||	t        |      t        j                         t        j                         	      }| j                  j                  |       |dz  } ||fS # t        $ r*}t!        d
| dt#        |              |dz  }Y d}~9d}~ww xY w)u(  
        Procesa los detalles de un asiento
        
        Args:
            seat_data: Datos del asiento de la API
            branch_office: Sucursal encontrada
            period: Período en formato YYYY-MM
            
        Returns:
            Tupla con (procesados, omitidos)
        r   asientorM   rQ   detallecuenta_glosar4   cuenta_codigobranch_office_idseat_idr;   accounting_accountamount
added_dateupdated_datez%Error procesando detalle del asiento rc   N)r   BANCO_ACCOUNTr,   r>   r   r?   r   r   r   r   idr%   r   nowaddrC   rB   r   )r.   r   r   r;   	processedskippedr   r   r   account_coder   r   eerrrF   s                 r   process_seat_detailszSeatClass.process_seat_details  sh    	--	2.&]]7B7$==B7 "	K!??>2d6H6HHqLG*C  $ww}}-=>EE$77<G %' 
 ..{LJ\] !%2%5%5#!'3v;'||~!) D!Q	;"	H '!!  =gYbQQR1s    #E$CE	E9E44E9resultsc           
         t               }|D ]  }	 |j                  dd      }|r|j                  d      ng }| j                  |      }|sDt	        d|r|d   nd        |xj
                  t        |j                  dg             z  c_        | j                  |||      \  }}	|xj                  |z  c_        |xj
                  |	z  c_        |xj                  dz  c_	         |S # t        $ rP}
t	        d	t        |
              |xj
                  t        |j                  dg             z  c_        Y d
}
~
/d
}
~
ww xY w)u  
        Procesa todos los resultados de la API externa
        
        Args:
            results: Lista de asientos de la API
            period: Período en formato YYYY-MM
            
        Returns:
            ProcessingStats con estadísticas del procesamiento
        rQ   rM   _zSucursal no encontrada para: r   zN/Ar   r4   zError procesando asiento: N)r    r   r   r   rB   r$   r   r   r"   r!   rC   r   )r.   r   r;   statsr   rQ   rw   r   r   r   rF   s              r   process_external_resultsz"SeatClass.process_external_resultsA  s:     !  	I!gr28=EKK$42! !% 7 78I J$9Rc:KA:Nin9opq))Sy"1M-NN) &*%>%>y-Y_%`"	7''94'%%0%%%*%#	0   23q6(;<%%Y]]9b-I)JJ%s    A=C(AC((	E1AD<<Ec                     	 | j                   j                  t              j                  t        j                  |k(        j                         }d}|D ]  }t        |j                  d|j                  |j                  |j                  t        j                         t        j                               }| j                   j                  |       |dz  } |S # t        $ r}t        dt        |             d}~ww xY w)u   
        Procesa las remuneraciones del período
        
        Args:
            period: Período en formato YYYY-MM
            
        Returns:
            Número de remuneraciones procesadas
        r   Nr   r4   z!Error procesando remuneraciones: )r,   r>   r   r?   r;   r   r   r   r   r   r   r   r   rC   r   )r.   r;   remunerationsprocessed_countremunerationr   rF   s          r   process_remunerationszSeatClass.process_remunerationsh  s    	J GGMM*;<CC!((F2ce   O - % %1%B%B '..'3'F'F'..'||~!) D!1$% #" 	J?AxHII	Js   CC 	C=!C88C=external_tokenc           
         	 | j                  ||      \  }}}t        d| d| d| d       | j                  |       | j                  ||||      }	|	j                  sdd|	j
                   dS | j                  |	j                  |      }
| j                  |      }||
_	        | j                  j                          |
j                  |
j                  z   }dd	| || d| |
j                  |
j                  |
j                  |
j                  |d
dS # t        $ rB}| j                  j!                          dt#        |       }t        |       d|dcY d}~S d}~ww xY w)u  
        Función principal para refrescar asientos contables
        
        Args:
            external_token: Token externo (para compatibilidad)
            rut: RUT para autenticación
            password: Password para autenticación
            month: Mes (1-12)
            year: Año
            
        Returns:
            Diccionario con el resultado del procesamiento
        u    Iniciando refresh para período z (z a )Fz!Error obteniendo datos externos: rd   Tz'Asientos procesados correctamente para )r!   r"   r#   r$   total_processed)r   messager;   
date_ranger   zError al procesar asientos: N)r<   rB   rG   ro   r   r   r   r   r   r#   r,   rA   r"   r!   r$   rC   rD   r   )r.   r   r[   r\   r0   r1   r9   r:   r;   
api_resultr   remuneration_countr   rF   	error_msgs                  r   refreshzSeatClass.refresh  s   2	#'#7#7t#D E5&4VHBugSqQR $$V, 11%XNJ%%$@AQAQ@RS  11*//6JE "&!;!;F!C,>E) GGNN#558U8UUO  DVHM !&s5'2','<'<).)@)@/4/L/L','<'<'6   	GG6s1vh?I) " 		s%   A-D 0B$D 	E 7EE E )r   r   r   r   rg   rJ   r   r/   r%   r   r   r<   rG   r   rK   rZ   r   ro   rv   r   r   r   r   r   r   r   r   r    r   r   r   r   r   r   r'   r'      s   1 R7NM2$S $ $c3m8L $*L# L$ L"
c3h 

s 
3 
4S> 
"0Q 0QS 0Qs 0Qc 0QV_ 0Qf3 3 =DI =(K\B] =~(,D (,IY@Z (,,/(,49(,T7"d 7"CT 7"#&7"+0c?7"r%T
 %C %O %N!JC !JC !JF@c @ @s @3 @VY @^b @r   r'   )app.backend.db.modelsr   r   r   r   (app.backend.classes.authentication_classr   r   calendarr
   re   r_   typingr   r   r   r   dataclassesr   r   r    r'   r   r   r   <module>r      s_    c c H     . . !
        r rr   