o
    FkiD                    @   s  d dl mZmZ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mZmZ d dlZd dlZd dl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Zd	Zejed
d ejej de!ej"#ede$ gd e%e&Z'ee&Z(dZ)dZ*dZ+dZ,dZ-dZ.de, de- de) de* de+ de./dd de(j0d< de(j0d< d e(j0d!< de(j0d"< ee( e
e(Z1G d#d$ d$e1j2Z3G d%d& d&e1j2Z4e(j5d'd(gd)d*d+ Z6G d,d- d-Z7d.d/ Z8e7 Z9e(5dd0d1 Z:e(5d2d3d4 Z;e(5d5d6d7 Z<e(5d8d9d: Z=e(5d;d<d= Z>e(j5d>d(gd)d?d@ Z?e(j5d>dAgd)dBdC Z@e(j5dDdEgd)dFdG ZAe(j5dDdHgd)dIdJ ZBe(j5dKd(gd)dLdM ZCe(j5dNd(gd)dOdP ZDe(j5dQdAgd)dRdS ZEdTdU ZFdVdW ZGdXdY ZHe(j5dZd(gd)d[d\ ZIe(j5d]d(gd)d^d_ ZJe(j5d`d(gd)dadb ZKe(j5dcd(gd)ddde ZLe(j5dfdAgd)dgdh ZMe(j5didAgd)djdk ZNe(j5dldAgd)dmdn ZOe(j5dod(gd)dpdq ZPe(j5drd(gd)dsdt ZQe(j5dudAgd)dvdw ZRe(j5dxd(gd)dydz ZSe(j5d{d(gd)d|d} ZTe(j5d~d(gd)dd ZUe(j5dd(gd)dd ZVe(Wddd ZXe(Wddd ZYe(WeZdd Z[dd Z\e&dkrWe(]  e\  W d   n	1 sRw   Y  e&dkre^d e^d e^d e^d e'_d z'e(]  e1j`aed e'_d e8  W d   n	1 sw   Y  W n eZy Zb ze'cdedeb  W Y dZb[bndZb[bww e^d e^d e^d e^d e^d e^d e^d e^d e(jeddd
d
d e(ZfdS )    )Flaskrequestjsonify	send_filerender_templatesend_from_directory)CORS)
SQLAlchemy)text)datetime	timedeltaN)Path)DictListOptionalAnyz#/var/www/html/TransmisionesMig/logsT)exist_okz4%(asctime)s - %(name)s - %(levelname)s - %(message)szreporte_mensual.log)levelformathandlers	localhost1433TRANSMISIONESMIGsazSistemas123*/zODBC Driver 17 for SQL Serverzmssql+pyodbc://:@/z?driver= +z'&TrustServerCertificate=yes&Encrypt=yesSQLALCHEMY_DATABASE_URIFSQLALCHEMY_TRACK_MODIFICATIONSz8K8m2#D9v$L4x@R7n*W5q&F1s!P6j%T3y^B8e@N7k$H4m*V9r&L2x#Q5w
SECRET_KEYDEBUGc                   @   s   e Zd ZdZejejddZejedddZ	ejedddZ
ejedddZeedZeedZeed	Zejejdd
Zejejejd
ZejejejejdZejddddfZejddddZdd ZdS )EmpresaClienteEmpresas_ClientesTprimary_key   Fnullable   2     default)r.   onupdateNITNombreComercialUQ_NIT_NombreComercialnameControlReportesempresa_clientedynamic)backreflazyc                 C   sx   | j | jpd| jp
d| jpd| jpd| jpd| jpd| jd ur$t| jnd| j	r-| j	
 nd | jr8| j
 d
S d d
S )N T)
idrazon_socialnombre_comercialnitemailtelefono	direccionactivofecha_creacionfecha_modificacion)IDRazonSocialr1   r0   EmailTelefono	DireccionActivoboolFechaCreacion	isoformatFechaModificacionself rQ   %/var/www/html/TransmisionesMig/app.pyto_dictL   s   
zEmpresaCliente.to_dictN)__name__
__module____qualname____tablename__dbColumnIntegerrE   StringrF   r1   r0   rG   rH   rI   BooleanrJ   DateTimer   utcnowrL   rN   UniqueConstraint__table_args__relationshipreportesrS   rQ   rQ   rQ   rR   r#   9   s    r#   c                   @   s>  e Zd ZdZejejddZejedddZ	ejeje
dddZejejdejdZejejdd	Zeed
Zejejdd	Zejejdd	Zejedddd	Zejedddd	ZeejZeejZeejZejejdd	ZejejddZejedddZejddddfZ dd Z!dS )r5   Control_ReportesTr%      Fr(   zEmpresas_Clientes.ID)r)   r.   r-   r,   r            r+   Periodo	ClienteID_periodo_cliente_ucr3   c                 C   s  d }| j r | j j| j j| j j| j j| j j| j j| j j| j jd}d }d }z| j	r.t
| j	}W n   Y z| jr>t
| j}W n   Y t| jpId}t| jpPd}d}d}d}d}	|rlt|dd}t|dd}|r~t|dd}t|dd}	|| }
||	 }|
|ks||krtd| j||
 |dkr|dkr|}|}n|dkr|dkr|}|}	n|dkr|dkr|}|}|||r|ddnd|r|ddnd|r|ddnd|rt|d	dnd|rt|d
dnd|rt|ddndt|dkr	|| d nddd	}||	ddd|rt|d	dnd|r+t|d
dnd|r7t|ddndt|dkrD|	| d nddd	}i d| jd| jd| jd|d| jrd| j nd d|d|dt| jpsddt| jp|dd| jd| jrdndd| jd|d|dt| j d| j!r| j! nd d| j"| j rd nd!|rd"|d# |d$ nd%|r|d& nd |r|d# nd |r|d$ d'S d d'S )(N)r;   r<   r=   r>   r?   r@   rA   rB   r   total_documentosdocumentos_exitososzODiscrepancia en datos del reporte ID {0}: Total guardado={1}, Suma detalles={2}documentos_recibidosdocumentos_aceptadosdocumentos_rechazadostotal_subtotal	total_ivatotal_valord   rf   	rk   rl   rm   rn   ro   rp   rq   rr   
tasa_exitor;   periodo
cliente_idclientefecha_enviovalor_totalru   observacionesstatus	completedpendingcontenido_completodetalle_facturasdetalle_gastos	facturadofecha_facturacionnumero_factura	Facturado	Pendientez	{0} ({1})r=   r>   Cliente no encontrador<   )estado_facturacioncliente_info_resumidacliente_razon_socialcliente_nombre_comercialcliente_nit)#r6   rE   rF   r1   r0   rG   rH   rI   rJ   DetalleFacturasjsonloadsDetalleGastosintTotalDocumentosDocumentosExitososgetloggerwarningr   floatroundrh   ri   
FechaEnviorM   
ValorTotal	TasaExitoObservacionesEnviadoContenidoCompletorK   r   FechaFacturacionNumeroFactura)rP   cliente_infodetalle_facturas_rawdetalle_gastos_raw
total_docstotal_exitososfacturas_totalfacturas_exitososgastos_totalgastos_exitosos
suma_totalsuma_exitososr   r   rQ   rQ   rR   rS   t   s   	

zControlReportes.to_dictN)"rT   rU   rV   rW   rX   rY   rZ   rE   r[   rh   
ForeignKeyri   r]   r   r^   r   r\   r   r   r   r   Numericr   r   Textr   r   r   r   r   r   r_   r`   rS   rQ   rQ   rQ   rR   r5   [   s(    r5   z/api/facturacion-por-clienteGET)methodsc               
   C   sj  zt jdt j} t jd}g }| r9|r-|  dt|d }|t	j
|k n|t	j
|  d tjt	ttt	jtjkt	jdk}|rZ|D ]}||}qR|t	j
  }i }|D ]p\}}	|	j}
|
|vr|	j|	j|	j|	j|	j|	j|	jdg dd	dd	d
||
< ||
 d |j
|j|jt |j!pdt |j"pd|j#r|j#$ ndd ||
 d  |jpd7  < ||
 d  t |j!pd7  < ||
 d  d7  < qh|% D ]}|d dkrt&dd |d D }t'||d  d|d< qt(d| |t)|t*|% dW S  t+y4 } zt,-dt|  t(dt|ddfW  Y d}~S d}~ww )uI   Obtiene resumen de facturación agrupado por cliente - útil para carterayearmonth-rf   -%T)r;   r<   r=   r>   r?   r@   rB   r           )rx   rb   rk   rr   periodos_reportadostasa_exito_promediorb   N)rv   rk   rl   rz   ru   ry   rk   rr   r      c                 s   s    | ]}|d  V  qdS )ru   NrQ   ).0rrQ   rQ   rR   	<genexpr>9  s    z.get_facturacion_por_cliente.<locals>.<genexpr>r   )successr   r   total_clientesclientes_facturacionu+   Error obteniendo facturación por cliente: Fr   errorr,   ).r   argsr   r   nowr   strzfillappendr5   rh   likerX   sessionqueryr#   joinri   rE   filterr   order_bydescallrF   r1   r0   rG   rH   rJ   r   r   r   r   r   r   rM   valuessumr   r   lenlist	Exceptionr   r   )r   r   filtersperiod_filterr   filter_conditionrb   r   reporterx   cliente_keycliente_data
tasa_totalerQ   rQ   rR   get_facturacion_por_cliente   s   	



r   c                   @   sR  e Zd ZdZdd Zd!dededeee	f fdd	Z
deee	f fd
dZdeee	f deee	f deee	f fddZdededededeee	f deee	f deee	f defddZdededeee	f dedeee	f deee	f defddZdeeee	f  fddZdedeeee	f  fddZdedeeee	f  fdd ZdS )"ReportManageruB   Maneja la generación y gestión de reportes mensuales por clientec                 C   s   d S NrQ   rO   rQ   rQ   rR   __init__O  s   zReportManager.__init__Nrw   target_datereturnc                 C   s  |du rt  }t |j|jdtdd }|d}t |j|jd}t |j|jt|j|jd ddd}tj	
|}|sGdd| d	|d
S td|j d| d| d| d	 zctj	j||dd }|rvdd|j d| |d
W S | |||}	| |||}
| |	|
}| ||||||	|
}| |||||	|
}td|j d|  dd|j d| || ||dW S  ty } ztd| dt|  ddt| |d
W  Y d}~S d}~ww )u5   Genera el reporte mensual para un cliente específicoNr   )daysz%Y-%m   ;   FzCliente con ID  no encontrado)r   messageperiodzGenerando reporte para cliente u    - período  ( - )Trh   ri   r   z%Ya existe un reporte para el cliente u    en el período z+Reporte generado exitosamente para cliente z#Reporte generado exitosamente para )r   r   r   rx   	report_id
statisticsz-Error generando reporte mensual para cliente : Error generando reporte: )r   r   r   r   r   strftimecalendar
monthranger#   r   r   r   inforF   r5   	filter_byfirst!_get_invoice_statistics_by_client!_get_expense_statistics_by_client_combine_statistics_generate_report_content_save_reportrS   r   r   r   )rP   rw   r   todayr   
start_dateend_daterx   existing_reportinvoice_statsexpense_statscombined_statsreport_contentr   r   rQ   rQ   rR   generate_monthly_reportR  sX   
&
&	z%ReportManager.generate_monthly_reportc              
   C   s   dddddddddd	S )u   Retorna estadísticas vacíasr   r   rt   rQ   rO   rQ   rQ   rR   _empty_stats  s   zReportManager._empty_statsr   r   c                 C   s\   i }|  D ]}|| ||  ||< q|d }|d }t|dkr&|| d ndd|d< |S )u.   Combina las estadísticas de facturas y gastosrk   rl   r   rs   rf   ru   )keysr   )rP   r   r   combinedkeytotalexitososrQ   rQ   rR   r     s   "z!ReportManager._combine_statisticsr   r   r   rx   r   c                 C   sT  g d}||j d  }	|j}
g }|d |d |dt d  |d|	 d|
  |d	 |d
 |d |d |d |d |d	 |d |d |d|j  |d|j  |d|j  |j	r|d|j	  |j
r|d|j
  |jr|d|j  |d	 |d |d	 |d |d |d|j  |d|d d|d  |d dkr|d|d d |d |d! d |d"|d# d$d% |d&|d' d( n
|d)|j d* |d	 |d dkrx|d+ |d, |d	 |d- |d.|d d |d/|d! d |d0|d |d!  d |d	 |d1 |d2|d# d$d% |d3d4|d#  d$d% |d	 |d5 |d6|d7 d( |d8|d9 d( |d:|d' d( |d	 |d; |d< |d	 |d dkr|d dkr|d! |d  d4 nd}|d= |d.|d d |d>|d! dd?|d$d@ |dA|d |d!  dd?d4| d$d@ |dB|d' d( |d	 |d dkrx|d dkr0|d! |d  d4 nd}|dC |d.|d d |d>|d! dd?|d$d@ |dA|d |d!  dd?d4| d$d@ |dB|d' d( |d	 |d |dD |dE |dF |dG |d	 |dH |dI |d dJ|S )KuC   Genera el contenido textual del reporte para un cliente específico)EneroFebreroMarzoAbrilMayoJunioJulioAgosto
SeptiembreOctubre	Noviembre	Diciembrer   u8   REPORTE MENSUAL CONSOLIDADO DE FACTURACIÓN ELECTRÓNICAzA=================================================================u   Fecha de generación: z%d/%m/%Y %H:%M:%Su   Período analizado: r   r:   u   INFORMACIÓN DEL PROVEEDOR:z------------------------------u#   Razón Social: TransmisionesMig SASz"Nombre Comercial: TransmisionesMigu#   Servicio: Facturación Electrónicau   INFORMACIÓN DEL CLIENTE:u   Razón Social: zNombre Comercial: zNIT: zEmail: u   Teléfono: u   Dirección: zRESUMEN EJECUTIVOz--------------------z	Cliente: u   Período de facturación: z%d/%m/%Yr   rk   r   zTotal documentos procesados: ,z&Documentos transmitidos exitosamente: rl   u   Tasa de éxito: ru   z.2f%zValor total facturado: $rr   z,.2fz"No se encontraron documentos para u    en este período.u$   DETALLE DE FACTURACIÓN ELECTRÓNICAz(========================================u0   Estadísticas de Documentos (Facturas y Gastos):z- Total Documentos: z(- Documentos Transmitidos Exitosamente: z- Documentos NO Transmitidos: zIndicadores de Efectividad:u    - Tasa de Transmisión Exitosa: u"   - Tasa de Fallos en Transmisión: rs   zResumen Financiero:z- Subtotal: $rp   z- IVA: $rq   z
- Total: $zDETALLE POR TIPO DE DOCUMENTOz#===================================u   Facturas Electrónicas:z- Transmitidos Exitosamente: r   z%)z- NO Transmitidos: z- Valor Total: $zDocumentos de Gastos:zNOTA IMPORTANTE:zEEste reporte incluye documentos de las tablas fe_documentos y Gastos1u(   procesados durante el período indicado.uY   Solo se evalúa el estado de transmisión (transmitido/no transmitido) para ambas tablas.z7Para cualquier consulta sobre este reporte, contacte a:u=   TransmisionesMig SAS - Servicios de Facturación Electrónica
)r   r   r   r   r   r   rF   r1   r0   rG   rH   rI   r   )rP   r   r   r   rx   r   r   r   month_names
month_namer   contenttasa_exito_facturastasa_exito_gastosrQ   rQ   rR   r     s   















"












&
 ,
&
 ,










z&ReportManager._generate_report_contentr  c           	      C   s   z/t ||t dd|d |d |d |d |t|t|d}tj| tj  |j	W S  t
yK } ztj  tdt|   d	}~ww )
uB   Guarda el reporte en la base de datos con información del clienteTu!   Reporte generado automáticamenterk   rl   rr   ru   rh   ri   r   r   r   r   r   r   r   r   r   r   zError guardando reporte: N)r5   r   r^   r   dumpsrX   r   addcommitrE   r   rollbackr   r   r   )	rP   r   rw   r   r  r   r   reportr   rQ   rQ   rR   r   %  s0   

zReportManager._save_reportc              
   C   sd   zt jt j  }dd |D W S  ty1 } ztdt	|  g W  Y d}~S d}~ww )u7   Obtiene todos los reportes con información del clientec                 S      g | ]}|  qS rQ   rS   r   r"  rQ   rQ   rR   
<listcomp>F      z1ReportManager.get_all_reports.<locals>.<listcomp>Error obteniendo reportes: N)
r5   r   r   rh   r   r   r   r   r   r   )rP   reportsr   rQ   rQ   rR   get_all_reportsB  s   zReportManager.get_all_reportsr   c              
   C   sb   zt j|}|r| W S dW S  ty0 } ztd| dt|  W Y d}~dS d}~ww )z)Obtiene el detalle completo de un reporteN%Error obteniendo detalle del reporte r   )r5   r   r   rS   r   r   r   r   )rP   r   r"  r   rQ   rQ   rR   get_report_detailK  s   zReportManager.get_report_detailc              
   C   sr   zt jj|dt j  }dd |D W S  ty8 } zt	d| dt
|  g W  Y d}~S d}~ww )4   Obtiene todos los reportes de un cliente específicori   c                 S   r#  rQ   r$  r%  rQ   rQ   rR   r&  X  r'  z7ReportManager.get_reports_by_client.<locals>.<listcomp>&Error obteniendo reportes del cliente r   N)r5   r   r   r   rh   r   r   r   r   r   r   )rP   rw   r)  r   rQ   rQ   rR   get_reports_by_clientT  s   z#ReportManager.get_reports_by_clientr   )rT   rU   rV   __doc__r   r   r   r   r   r   r  r  r   r#   r   r   r   r*  r   r,  r0  rQ   rQ   rQ   rR   r   L  s6     D.



t


	"	r   c               
   C   sn   zt   td t j  td W dS  ty6 }  ztd|   t j  W Y d} ~ dS d} ~ ww )u'   Crear todas las tablas automáticamenteu+   ✓ Tablas creadas/verificadas exitosamenteu   ✓ Clientes de ejemplo creadosu   ✗ Error creando tablas: NF)	rX   
create_allr   r   r   r   r   r   r!  r   rQ   rQ   rR   crear_tablas^  s   


r4  c               
   C   sV   zt dW S  ty* }  ztdt|   dt|  dfW  Y d} ~ S d} ~ ww )u   Página principalz
index.htmlu"   Error cargando página principal: u   Error cargando la aplicación: r,   N)r   r   r   r   r   r3  rQ   rQ   rR   indexr  s   
r5  z/static/<path:filename>c              
   C   sN   zt d| W S  ty& } ztd|  dt|  W Y d}~dS d}~ww )u   Servir archivos estáticosz%/var/www/html/TransmisionesMig/staticu"   Error sirviendo archivo estático r   NzArchivo no encontrado  )r   r   r   r   r   )filenamer   rQ   rQ   rR   static_files{  s   r9  z/testc                   C   s   t ddt  dS )zEndpoint de pruebaokz"Servidor funcionando correctamente)r|   r   	timestamp)r   r   r   rM   rQ   rQ   rQ   rR   test  s
   
r<  z/test-dbc               
   C   s   z%t jtd tj } tj }tdd| |t	j
d dd dW S  tyL } ztdt|  td	t|d
dfW  Y d}~S d}~ww )u    Probar conexión a base de datosSELECT 1r:  zBase de datos conectadar   r   r   )r|   r   clientes_countreportes_countdb_urizError en test-db: r   r|   r   r,   N)rX   r   executer
   r#   r   countr5   r   appconfigsplitr   r   r   r   )r>  r?  r   rQ   rQ   rR   test_db  s*   


rG  z/init-dbc               
   C   s~   zt  } | rtdddW S tddddfW S  ty> } ztdt|  tdt|ddfW  Y d	}~S d	}~ww )
zInicializar base de datosTz(Base de datos inicializada correctamenter   r   Fz%Error al inicializar la base de datosr,   zError en init-db: r   N)r4  r   r   r   r   r   )	resultador   rQ   rQ   rR   init_database  s.   
rJ  z/api/clientesc               
   C   s|   zt jjddt j } tdd | D W S  ty= } zt	dt
|  tdt
|idfW  Y d}~S d}~ww )	zObtiene la lista de clientesTrJ   c                 S   r#  rQ   r$  )r   rx   rQ   rQ   rR   r&    r'  z get_clientes.<locals>.<listcomp>zError obteniendo clientes: r   r,   N)r#   r   r   r   rF   r   r   r   r   r   r   )clientesr   rQ   rQ   rR   get_clientes  s    rM  POSTc                  C   sd  zt  } g d}|D ]}| |s"tdd| dddf  W S qtjj| d d }|r?tdd	| d  ddfW S t| d
 | d | d | dd| dd| dd| ddd}tj	
| tj	  td|j d|j d tdd| ddfW S  ty } z tdt|  tj	  tdt|ddfW  Y d}~S d}~ww )zCrea un nuevo clienter<   r=   r>   Fz	El campo z es obligatorior     r>   r0   zYa existe un cliente con NIT r<   r=   r?   r:   r@   rA   rB   TrF   r1   r0   rG   rH   rI   rJ   zCliente creado: z (NIT: r   zCliente creado exitosamenter   r   rx      zError creando cliente: r,   N)r   get_jsonr   r   r#   r   r   r   rX   r   r  r   r   r   rF   r0   rS   r   r   r   r!  )datarequired_fieldsfieldexistingrx   r   rQ   rQ   rR   create_cliente  sd   









rZ  z/api/clientes/<int:cliente_id>PUTc              
   C   s>  zot j| }|stddddfW S t }d|v r |d |_d|v r)|d |_d|v r2|d |_d|v r;|d |_	d	|v rD|d	 |_
d
|v rM|d
 |_t |_tj  td|j d|j d tdd| dW S  ty } z#td|  dt|  tj  tdt|ddfW  Y d}~S d}~ww )zActualiza un clienteFr   r   r7  r<   r=   r?   r@   rA   rB   Cliente actualizado:  (ID: r   Tz Cliente actualizado exitosamenterS  zError actualizando cliente r   r,   N)r#   r   r   r   r   rU  rF   r1   rG   rH   rI   rJ   r   r^   rN   rX   r   r   r   r   rE   rS   r   r   r   r!  )rw   rx   rV  r   rQ   rQ   rR   update_cliente  sR   









r^  DELETEc              
   C   s   z`t j| }|stddddfW S tjj| d }|dkr8d|_t	 |_
tj  d|j d| d	}n|j}tj| tj  d| d
}td|j d|  d td|dW S  ty } z#td|  dt|  tj  tdt|ddfW  Y d}~S d}~ww )z"Desactiva un cliente (soft delete)Fr   r   r7  r.  r   zCliente z desactivado (tiene z reportes asociados)z eliminado completamentezCliente eliminado/desactivado: r]  r   TrH  zError eliminando cliente r   r,   N)r#   r   r   r   r5   r   rC  rJ   r   r^   rN   rX   r   r   rF   deleter   r   r   r   r   r!  )rw   rx   r?  r   r<   r   rQ   rQ   rR   delete_cliente(  sF   




ra  z'/api/clientes/<int:cliente_id>/reportesc              
   C   s   z"t j| }|stddddfW S t| }td| |dW S  tyL } zt	d|  dt
|  tdt
|dd	fW  Y d
}~S d
}~ww )r-  Fr   r   r7  T)r   rx   rb   r/  r   r,   N)r#   r   r   r   report_managerr0  rS   r   r   r   r   )rw   rx   rb   r   rQ   rQ   rR   get_reportes_by_clienteT  s2   

rc  z/api/test-pos-connectionc               
   C   sp   zt ddt  ddddW S  ty7 }  ztdt|   t dt| d	d
fW  Y d} ~ S d} ~ ww )z/Endpoint para que el POS pruebe la conectividadr:  u   Conexión desde POS exitosazReportes Web MIGz1.0zTransmisionesMig POS)r|   r   r;  serverversioncliente_sistemazError en test-pos-connection: r   rA  r,   N)r   r   r   rM   r   r   r   r   r3  rQ   rQ   rR   test_pos_connectionn  s&   

rg  z/api/reportes-desde-posc            
   
   C   sl  zt  } td| d  g d}|D ]}| |s,tdd| ddf  W S q| d }t|}|sAtdd	ddfW S | d }tjj	||j
d
d }|rbt||  d| d|j }nt|j
| }d| d|j }td|  td
||j
|j|j|jd|dW S  ty }	 ztdt|	  tddt|	 ddfW  Y d}	~	S d}	~	ww )z-Recibe reportes enviados desde el sistema POSu.   📥 Recibiendo reporte desde POS - Período: rv   )rv   ry   empresaFCampo requerido faltante: r   rP  rh  z%No se pudo crear/verificar el clienteTr   zReporte z actualizado para z creado para u   ✅ r;   r<   r=   r>   )r   r   rx   rv   u(   ❌ Error recibiendo reporte desde POS: Error interno: r,   N)r   rU  r   r   r   r   #verificar_o_crear_cliente_desde_posr5   r   r   rE   r   actualizar_reporte_existenterF   crear_reporte_desde_posr1   r0   r   r   r   )
rV  rW  rX  empresa_datarx   r   r   mensajer   r   rQ   rQ   rR   recibir_reporte_desde_pos  sp   



rq  c           
   
   C   s  z|  dpd }|  dpd }|std W d S tjj||d }|rvd}|  d}|r<|j|kr<||_d	}|  d
}|rM|j	|krM||_	d	}|  d}|r^|j
|kr^||_
d	}|rst |_tj  td|j  |W S t|  dp}d|||  d
pd|  dpddd	d}tj| tj  td|j d| d |W S  ty }	 ztdt|	  tj  W Y d }	~	d S d }	~	ww )Nr>   r:   r=   zSin Definiru   ⚠️ NIT vacío)r0   r1   Fr<   Tr?   r@   r\  rR  zNuevo cliente: r   r   z.Error en verificar_o_crear_cliente_desde_pos: )r   stripr   r   r#   r   r   r   rF   rG   rH   r   r^   rN   rX   r   r   r   r1   r  r   r   r   r!  )
ro  r>   r=   rx   actualizador<   r?   r@   nuevo_clienteexrQ   rQ   rR   rl    sd   








rl  c              
   C   s   zJ| dr|d | _| dr|d | _| dr|d | _| dr)|d | _| dr3|d | _dt d | _	t
 | _tj  W d	S  tyl } ztdt|  tj  W Y d	}~d	S d	}~ww )
z0Actualiza un reporte existente con datos del POSrk   rl   rz   ru   r   zActualizado desde POS - %Y-%m-%d %H:%M:%Sz&Error actualizando reporte existente: N)r   r   r   r   r   r   r   r   r   r   r^   r   rX   r   r   r   r   r   r   r!  )r   rV  r   rQ   rQ   rR   rm    s&   










rm  c                 C   s   zMt |d | t ddt d |dd|dd|dd|d	d|d
dt|di t|di d}tj	
| tj	  |jW S  tyo } ztdt|  tj	  W Y d}~dS d}~ww )z)Crea un nuevo reporte desde datos del POSrv   TzCreado desde POS - rv  rk   r   rl   rz   ru   r   r:   r   r   r  z!Error creando reporte desde POS: N)r5   r   r^   r   r   r   r   r  rX   r   r  r   rE   r   r   r   r   r!  )rw   rV  nuevo_reporter   rQ   rQ   rR   rn    s0   






rn  z/api/statusc            	   
   C   s  zzt jtd d} W n   d} Y d}| rVz!tjtj 	 }|r8|j
|j |jr4|j ndd}W n tyU } ztdt|  W Y d}~nd}~ww | ratjjdd nd}| rjtj nd}t }|jd	k rt|j|jd
 d
nt|jd
 d
d
}t|j|jd}t| || t  ||dW S  ty } z tdt|  tdt|t  ddfW  Y d}~S d}~ww )u:   Obtiene el estado del sistema con información de clientesr=  TFN)rv   ry   rx   u"   Error obteniendo último reporte: rK  r      r   rg   )db_connectedlast_reportnext_report_datecurrent_timeclientes_activostotal_reporteszError obteniendo estado: )ry  r   r|  r,   )rX   r   rB  r
   r5   r   r   r   r   r   rh   rM   r6   rS   r   r   r   r   r#   r   rC  r   r   r   r   r   r   )	ry  rz  ultimor   r}  r~  r   
next_monthr{  rQ   rQ   rR   
get_status8  sX    0

	
r  z/api/reports/summaryc                  C   s:  zvt jtjtjtjtjtjtj	tj
tjtjtjtjtjttjtjktjdktj  } g }| D ]9}||j|j|j|j|j|jd|jrR|j nd|jpWd|j	p[dt|j
p`dt|jpfd|jrldndd
 q8t|W S  ty } ztdt|  td	t|id
fW  Y d}~S d}~ww )zAObtiene solo un resumen ligero de reportes (sin detalles pesados)TrO  Nr   r}   r~   
r;   rv   rw   rx   ry   rk   rl   rz   ru   r|   z&Error obteniendo resumen de reportes: r   r,   )rX   r   r   r5   rE   rh   ri   r   r   r   r   r   r   r#   rF   r1   r0   r   r   r   r   r   r   rM   r   r   r   r   r   r   )rb   resultr   r   rQ   rQ   rR   get_reports_summaryk  sb   

 r  z/api/reportsc               
   C   s   zt jd} | rtt| }nt }t|W S  ty? } zt	
dt|  tdt|idfW  Y d}~S d}~ww )u9   Obtiene la lista de reportes con información de clientesrw   r(  r   r,   N)r   r   r   rb  r0  r   r*  r   r   r   r   r   )rw   r)  r   rQ   rQ   rR   get_reports  s   
 r  z/api/reports/<int:report_id>c              
   C   s~   zt | }|rt|W S tddidfW S  ty> } ztd|  dt|  tdt|idfW  Y d}~S d}~ww )u,   Obtiene el detalle de un reporte específicor   Reporte no encontrador7  r+  r   r,   N)rb  r,  r   r   r   r   r   )r   r"  r   rQ   rQ   rR   r,    s   

 r,  z/api/generate-reportc               
   C   s   zEt  pi } | d}|stddddfW S d}d| v r0d| v r0tt| d t| d d	}t||}|d
 r?t|W S t|dfW S  tyo } zt	
dt|  tddt| ddfW  Y d}~S d}~ww )u;   Genera un nuevo reporte mensual para un cliente específicorw   FzEl cliente_id es obligatoriorH  rP  Nr   r   r   r   r   Error interno del servidor: r,   )r   rU  r   r   r   r   rb  r  r   r   r   r   )rV  rw   r   r  r   rQ   rQ   rR   generate_report  s6   

r  z/api/generate-all-reportsc               
   C   s  z_t  pi } d}d| v rd| v rtt| d t| d d}tjjdd }g }d}|D ]}t	|j
|}|| |d |d	 rI|d7 }q.tdd
| dt| d|t||dW S  ty } ztdt|  tddt| ddfW  Y d}~S d}~ww )z/Genera reportes para todos los clientes activosNr   r   r   TrK  r   )rx   r  r   Se generaron z reportes de 	 clientes)r   r   generated_counttotal_clientsresultsz2Error generando reportes para todos los clientes: Fr  rH  r,   )r   rU  r   r   r#   r   r   r   rb  r  rE   r   rS   r   r   r   r   r   r   )rV  r   rL  r  r  rx   r  r   rQ   rQ   rR   generate_all_reports  sD   
r  z/api/verify-missingc               
   C   s  zt jjdd } t }|j}|j}|d }d}g }| D ]}d}g }	tddD ]8}
| d|
d}t	jj||j
dd }|sat||
t||
d }t|j
|}|d	 ra|d7 }|	| q)td|D ]8}
| d|
d}t	jj||j
dd }|st||
t||
d }t|j
|}|d	 r|d7 }|	| qg||7 }|| ||	d
 qtd| dt|  d td|t| d| dt|  d|dW S  ty } ztdt|  tdddt| ddfW  Y d}~S d}~ww )z<Verifica y genera reportes faltantes para todos los clientesTrK  r   r      r   02dr   r   )rx   r  generated_periodsu'   Verificación completada. Se generaron z reportes faltantes para z
 clientes.r  r  )r   r  r  r   results_by_clientz&Error verificando reportes faltantes: Fr  )r   r  r   r,   N)r#   r   r   r   r   r   r   r   ranger5   rE   r   r   r   rb  r  r   rS   r   r   r   r   r   r   r   )rL  current_datecurrent_yearcurrent_monthprevious_yeartotal_generatedr  rx   r  r  r   r   rY  r   r  r   rQ   rQ   rR   verify_missing  sp   



r  z%/api/reports/<int:report_id>/downloadc              
   C   s   zVt | }|stddidfW S |dd}|s"tddidfW S t }||d |d |d	i }|d
d	dd}d| d|d  d}t
|d|ddW S  ty } ztd|  dt|  tdt|idfW  Y d}~S d}~ww )z$Descarga un reporte en formato textor   r  r7  r   r:   z#Contenido del reporte no disponiblezutf-8r   rx   r=   Clienter   _Reporte_rv   z.txtTz
text/plainas_attachmentdownload_namemimetypezError descargando reporte r   r,   N)rb  r,  r   r   ioBytesIOwriteencodeseekreplacer   r   r   r   r   )r   r"  r  bytes_bufferr   cliente_namer8  r   rQ   rQ   rR   download_reportI  s0   

 r  z/api/reports/exportc                  C   sL  zt jd} t jd}t jd}tjttttj	tj
ktjdk}| r5|tj	t| k}|rY|rMd|t|d}|tj|k}n|tjd|}|tjtj }|sntdd	id
fW S g }|D ]\}}zi|jd}	t|	d }
t|	d }| }|di }|di }t|dd}|dkr||j|j|jd|
||d t|dd}|dkr||j|j|jd|
||d td|j|j|| W qr ty	 } ztd|j
t| ddl }t|!  W Y d}~qrd}~ww |stddidfW S tdt"| t#j$|g dd}|j%g ddd}t&' }zAt#j(|dd/}|j)|dd d! |j*d }d"d"d#d$d%d%d&d'}|+ D ]\}}||j,| _-qZW d   n	1 sqw   Y  W n+ ty } ztd(t| tdd)t|idfW  Y d}~W S d}~ww |.d dg}| rtjt| }|r||j/d*d+ |r|t| |r|t|d d,d+|t01 2d-}t3|d|d.d/W S  ty% } z(td0t| ddl }t|!  tdd1t|idfW  Y d}~S d}~ww )2uY   Exporta reportes filtrados a Excel con formato de detalle de documentos por organizaciónrw   r   r   Tz{0}-{1}rf   z{0}-%r   z;No hay reportes para exportar con los filtros seleccionadosr7  r   r   r   r   r   rl   Factura)   OrganizaciónzNombre comercialz
NIT EmisorzTipo de documento   AñoMesCantidad	DocSopAdqzCExportando - Cliente: {0}, Periodo: {1}, Facturas: {2}, Gastos: {3}z!Error procesando reporte {0}: {1}Nz$No se pudieron procesar los reportesr,   zTotal de filas exportadas: {0})columns)r  r  r  )by	ascendingopenpyxl)engineReportesF)
sheet_namer5  (      re      rx  )ABCDEFGzError creando Excel: {0}z!Error al crear archivo Excel: {0}r   r  z{0}_{1}.xlsxz%Y%m%d_%H%M%SzAapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetr  zError exportando reportes: {0}zError interno al exportar: {0})4r   r   r   rX   r   r   r5   r#   r   ri   rE   r   r   r   r   r   r   rh   r   r   rF   r   r   rF  rS   r   r1   r0   r   r   r   r   	traceback
format_excr   pd	DataFramesort_valuesr  r  ExcelWriterto_excelsheetsitemscolumn_dimensionswidthr  r  r   r   r   r   )rw   r   r   r   r   rb   
excel_datar   rx   periodo_partsaniomesreporte_dictr   r   exitosos_facturasexitosos_gastosr   r  dfexcel_bufferwriter	worksheetcolumn_widthscolr  filename_partscliente_objr8  rQ   rQ   rR   export_reportsj  s   



(
&r  z"/api/actualizar-estado-facturacionc               
   C   s4  zt  } td| d  g d}|D ]}| |s,tdd| ddf  W S q| d }| d }| d	 }| d
 }zt|dd}W n   t	 }Y t
jj|d }|sjtdd| dddfW S tjj||jdd }	|	stdd| d|j dddfW S d|	_||	_||	_d| dt	 d }
|	jr|	 jd|
 7  _n|
|	_tj  td|j d| d|  tdd|j|j|j|jd|	j|	j|	j|	j|	jr|	j nddd W S  ty } z#td!t|  tj   tdd"t| dd#fW  Y d}~S d}~ww )$u>   Actualiza el estado de facturación de un reporte desde el POSu5   📋 Actualizando estado de facturación - Período: rv   )rv   r   r   r   Fri  r   rP  r   r   r   Tr   rQ  zCliente con NIT r   r7  Tr   u   Reporte para período z y cliente zFacturado desde POS - Factura #r   rv  z | u2   ✅ Estado de facturación actualizado - Cliente: u   , Período: z, Factura: u/   Estado de facturación actualizado exitosamenterj  N)r;   rv   r   r   r   )r   r   rx   r   u/   ❌ Error actualizando estado de facturación: rk  r,   )!r   rU  r   r   r   r   r   fromisoformatr  r   r#   r   r   r   r5   rE   rF   r   r   r   r   r   rX   r   r   r1   r0   rh   rM   r   r   r   r!  )rV  rW  rX  rv   r   r   fecha_facturacion_strr   rx   r   observaciones_facturacionr   rQ   rQ   rR   actualizar_estado_facturacion  s   






r  z$/api/reportes-pendientes-facturacionc            
      C   s  zt jd} t jd}t jd}tjttttj	tj
ktjdktjdk}| rQ|rE|  dt|d }|tj|k}n|tj|  d}|r[|tj	|k}|tj  }g }|D ]/\}}||j
|j|j|j|jt|jp~d	|jpd	|jpd	|jr|j nd
|jpdd
 qit dt!| d t"|W S  t#y }	 zt$dt|	  t"dt|	ddfW  Y d
}	~	S d
}	~	ww )u6   Obtiene reportes que están pendientes de facturaciónr   r   rw   TFr   rf   r   r   N)

reporte_idrv   r   r   r   rz   rk   rl   ry   r   u   📋 Obtenidos u$    reportes pendientes de facturaciónu*   ❌ Error obteniendo reportes pendientes: r   r,   )%r   r   r   rX   r   r   r5   r#   r   ri   rE   r   r   r   r   r   rh   r   r   r   r   r   r0   rF   r1   r   r   r   r   r   rM   r   r   r   r   r   r   )
r   r   rw   r   r   reportes_pendientesrI  r   rx   r   rQ   rQ   rR   #get_reportes_pendientes_facturacionb  s\   

r  z/api/reportes-facturadosc            
      C   s  zt jd} t jd}t jd}tjttttj	tj
ktjdktjdk}| rQ|rE|  dt|d }|tj|k}n|tj|  d}|r[|tj	|k}|tj  }g }|D ]8\}}||j
|j|j|j|jt|jp~d|jpd|jpd|jr|j nd	|j|j |jr|j nd	d
 qit!"dt#| d t$|W S  t%y }	 zt!&dt|	  t$dt|	ddfW  Y d	}	~	S d	}	~	ww )z+Obtiene reportes que ya han sido facturadosr   r   rw   Tr   rf   r   r   N)r  rv   r   r   r   rz   rk   rl   ry   r   r   r   u   💰 Obtenidos z reportes facturadosu*   ❌ Error obteniendo reportes facturados: Fr   r,   )'r   r   r   rX   r   r   r5   r#   r   ri   rE   r   r   r   r   r   rh   r   r   r   r   r   r   r0   rF   r1   r   r   r   r   r   rM   r   r   r   r   r   r   r   )
r   r   rw   r   r   reportes_facturadosrI  r   rx   r   rQ   rQ   rR   get_reportes_facturados  s`   

r  z/api/estadisticas-facturacionc            
      C   s  zt jdt j} tjtj	
|  dtjdk}| }|tjdk }|| }tjtjtjtj	
|  dtjdktjdk pNd}tjtjtjtj	
|  dtjdktjdk pod}t|dkr{|| d ndd}t|dkr|| d ndd}t| |||||t|t|t|| d	W S  ty }	 ztd	t|	  tdt|	d
dfW  Y d}	~	S d}	~	ww )u/   Obtiene estadísticas generales de facturaciónr   r   Tr   Frs   rf   )	r   r~  r  r  porcentaje_facturadoporcentaje_pendientevalor_total_facturadovalor_total_pendientevalor_total_generalu$   ❌ Error obteniendo estadísticas: r   r,   N)r   r   r   r   r   r   r5   r   r   rh   r   r   rC  r   rX   r   funcr   r   scalarr   r   r   r   r   r   r   )
r   reportes_queryr~  r  r  r  r  r  r  r   rQ   rQ   rR   get_estadisticas_facturacion  sp   	

r  z/api/reports/paginatedc                  C   s   zft tjdd} t tjdd}|dvrd}| dk r d} tjd}tjd}tjd}tjd	}tjd
d  }tjt	j
t	jt	jt	jt	jt	jt	jt	jt	jtjtjtjtt	jtj
kt	jdk}|rz|t	jt |k}|r|r| dt|d }|t	j|k}n|t	j| d}|r|dkr|t	jdk}n|dkr|t	jdk}|r|ttjd| dtjd| dtjd| dt	jd| d}|tj t	j  }|! }	|	| d | }
| d | }|"|#|$ }g }|D ]@}|%|j
|j|j|j|j|jd|jr.|j& nd|jp4d|jp9dt'|jp?dt'|jpFd|jrMdndd
 qt(d|| ||	|
| dk| |
k ddW S  t)y } zt*+dt|  t(dt|ddfW  Y d}~S d}~ww )u    Obtiene reportes con paginaciónpager   per_pagers   )rs      r,   i  rw   r   r   r|   searchr:   Tr   rf   r   r}   r~   Fr  rO  Nr   r  )r  r  r  total_pageshas_prevhas_next)r   rV  
paginationz%Error obteniendo reportes paginados: r   r,   ),r   r   r   r   rr  lowerrX   r   r   r5   rE   rh   ri   r   r   r   r   r   r   r#   rF   r1   r0   r   r   r   r   r   or_iliker   ascr   rC  offsetlimitr   r   rM   r   r   r   r   r   )r  r  rw   r   r   r|   r  r   r   r  r  r  rb   r  r   r   rQ   rQ   rR   get_reports_paginated  s   



r  r7  c                 C   sT   t dtj  tjdrtddidfS dtjv rdS tjdr(t	d	S d
S )Nz404 error: /api/r   zEndpoint no encontrador7  z/static/r6  z1/var/www/html/TransmisionesMig/templates/404.htmlz404.html)u   Página no encontradar7  )
r   r   r   urlpath
startswithr   osexistsr   r   rQ   rQ   rR   	not_found  s   
r  r,   c                 C   sZ   t dt|  dtj  tj  tj	dr!t
ddidfS tjdr+tdS d	S )
Nz500 error:  - URL: r  r   Error interno del servidorr,   z1/var/www/html/TransmisionesMig/templates/500.htmlz500.html)r  r,   )r   r   r   r   r  rX   r   r!  r   r  r   r  r  r   r  rQ   rQ   rR   internal_error  s
   
r  c                 C   s6   t dt|  dtj  tj  tddidfS )z Maneja excepciones no capturadasu   Excepción no capturada: r  r   r  r,   )	r   r   r   r   r  rX   r   r!  r   r3  rQ   rQ   rR   handle_exception  s   
r	  c               
   C   s   t d z)t  tjtd t d t  W d   W dS 1 s'w   Y  W dS  t	yK }  zt 
dt|   W Y d} ~ dS d} ~ ww )u2   Inicialización de la aplicación para producciónuG   Aplicación cargada para producción con Apache - Versión con Clientesr=  u4   ✅ Conexión a base de datos exitosa en producciónNu7   ❌ Error de conexión a base de datos en producción: )r   r   rD  app_contextrX   r   rB  r
   r4  r   r   r   r3  rQ   rQ   rR   initialize_app  s   


&"r  __main__z2==================================================u+   🚨 MODO DESARROLLO - SISTEMA CON CLIENTESu8   🚨 Esta aplicación maneja múltiples empresas clienteu1   Iniciando aplicación con gestión de clientes...r=  u%   ✅ Conexión a base de datos exitosau,   ❌ No se pudo conectar a la base de datos: z3
==================================================zURLs de prueba:z- http://localhost:8000/testz- http://localhost:8000/test-dbz- http://localhost:8000/init-dbz"- http://localhost:8000/api/statusz$- http://localhost:8000/api/clientesz3==================================================
z0.0.0.0i@  )hostportdebugthreaded)gflaskr   r   r   r   r   r   
flask_corsr   flask_sqlalchemyr	   
sqlalchemyr
   r   r   r   loggingr  pathlibr   r  pandasr  typingr   r   r   r   r   log_dirmakedirsbasicConfigINFOFileHandlerr   r   StreamHandler	getLoggerrT   r   rD  	DB_SERVERDB_PORTDB_DATABASEDB_USERNAMEDB_PASSWORD	DB_DRIVERr  rE  rX   Modelr#   r5   router   r   r4  rb  r5  r9  r<  rG  rJ  rM  rZ  r^  ra  rc  rg  rq  rl  rm  rn  r  r  r  r,  r  r  r  r  r  r  r  r  r  r  errorhandlerr  r  r   r	  r  r
  printr   r   rB  r   r   r   runapplicationrQ   rQ   rQ   rR   <module>   s(    
 



" 
V  





	
4
.
+


@?
2
3



(
B
 
 
Z
8
:
8
z








 