
    Ҁh                        d dl mZ d dlZd dlZd dlmZ d dlmZ d dlm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mZ d d	lmZ  e        ej*                  j-                  d
       d dlmZ d Zd Zd Zd Zd Zd ZdefdZ defdZ!defdZ"d5dede#de
jH                  fdZ%dedee&ef   fdZ'defdZ(d Z)d Z*defdZ+ded ee&e&f   dee&ef   fd!Z,d"e
jH                  de#fd#Z-d$ Z.d% Z/d& Z0d"e
jH                  dee&   fd'Z1d"e
jH                  de2e   fd(Z3	 	 	 d6d"e
jH                  d)ee&   d*e&d+e4dee&ef   f
d,Z5d"e
jH                  d-ee&e&f   de
jH                  fd.Z6d"e
jH                  de
jH                  fd/Z7d"e
jH                  de
jH                  fd0Z8d"e
jH                  de
jH                  fd1Z9d"e
jH                  de
jH                  fd2Z:d7d3Z;d4 Z<y)8    )HTTPExceptionN)datetime)List)
UploadFile)BytesIO)r   DictAnyOptional)load_dotenv)tabulatez/var/www/html/config)get_connectionc                  *   	 t               } | dddS | j                  d      }d}|j                  |       |j                         }|j	                          | j	                          dd|d	S # t
        $ r}dd
t        |       dcY d }~S d }~ww xY w)Nr      Error de conexiónsuccessmessageT
dictionaryzMSELECT * FROM listado_tablas_prospectos WHERE estado_contacto  = 'Prospectos'   ztablas obtenidas correctamenter   r   dataError: )r   cursorexecutefetchallclose	Exceptionstr)
conexionBDr   queryuserDataes        Q/var/www/dev.api.imparables.com.co/api_imparables/crm/procesos/contactabilidad.pygetListaTablasr$      s    
#%
/ 
 ""d"3_u??$ 7
 	

  
 Q)
 	

s#   A. AA. .	B7BBBc                  p   	 t               } | dddS | j                  d      }d}|j                  |       |j                         }g }t	        |      dkD  r|D cg c]  }|d   	 }}|j                          | j                          |S c c}w # t        $ r}ddt        |       dcY d }~S d }~ww xY w)	Nr   r   r   Tr   z'SELECT * FROM listado_tablas_prospectosnombre_tablar   )r   r   r   r   lenr   r   r   )r   r   r    tablasnombre_tablasitemr"   s          r#   traer_tablas_permitidasr+   6   s    
#%
/ 
 ""d"39u"v;?>DEdT.1EME F  
 Q)
 	

s5   B A	B B(#B B 	B5B0*B50B5c                   K   	 t               }|Addddt               v rj                          dt               v r|r|j                          S S S | j                  d      }| j                  d      }| j                  dd      }|t	        |      nd }t               }t        |      dk(  rAd	d
ddt               v rj                          dt               v r|r|j                          S S S ||vrAd	dddt               v rj                          dt               v r|r|j                          S S S |j                  d      }d| d}g }	||dz  }|	j                  |       |dz  }|	j                  |       |j                  |t        |	             |j                         }
d| d}|j                  |       |j                         d   }|
D ]  }|j                  dd       |d<    d }t        |
      |k(  r
|
r|
d   d   }dd|
||ddt               v r|j                          dt               v r|r|j                          S S S # t        $ rW}d	dt        |       dcY d }~dt               v rj                          dt               v rr|j                          S S S d }~ww xY w# dt               v rj                          dt               v rr|j                          w w w xY ww)Nr   r   r   r   r   tablaSeleccionadapageSize   Fz#No se encontraron tablas permitidaszTabla no permitidaTr   zp
            SELECT 
                t.*, e.estado_etapa AS estado_etapa_desc
            FROM 
                z t
            LEFT JOIN 
                estados_etapas e ON t.estado_etapa = e.id
            WHERE 
                t.estado_etapa IN (1, 5)
        z AND t.id > %szN
            ORDER BY 
                t.id DESC
            LIMIT %s
        z7
            SELECT COUNT(*) AS total
            FROM z6 t
            WHERE t.estado_etapa IN (1, 5)
        totalestado_etapa_descestado_etapaidzDatos obtenidos correctamente)r   r   r   
nextCursortotalRecordsr   )r   localsr   getintr+   r'   r   appendr   tupler   fetchoner   r   )r   r   r   tabla
cursor_val	page_size	cursor_idtablas_validasr    params	registroscount_queryr0   registronext_cursorr"   s                   r#   datos_tabla_seleccionadarG      s7    a#%
/v vxLLN68#
 )3#q ,-XXh'
HHZ+	 (2'=C
O4	 12~!# @X vxLLN68#
 )3#S & /L vxLLN68#
 )3#G ""d"3  			   %%EMM)$ 	  	
 	i  	ueFm,OO%	 	
 	{#!'* " 	OH'/||4G'NH^$	O y>Y&9#B--K 6%!
 vxLLN68#
 )3#  
 Q)
 	

 vxLLN68#
 )3#
 vxLLN68#
 )3#sk   K-I	 =K-AI	 0=K--I	 5=K-2CI	 =K-		J)J$"J)#J, '=K-$J))J, ,>K**K-c                 @   t               }d }|dddS 	 |j                  dd      }t        d|        t        d|        |dvr*dd	d|r|j                          |r|j                          S S |j                  d
d       }|j                  dd       }|j                  dd       }|j                  dd       }|j                  dd       }	|j                  dd       }
|j                  dd       }|j                  dd       }|j                  dd       }|j                  dd       }|j                  dd       }|j                  dd       xs d}|j                  dd       xs d}|j                  dd       }|j                  dd       }|j                  dd       }|j                  dd       }|j                  dd       }|j                  dd       }|j                  dd       }|j                  d d       }|j                  d!d       }|j                  d"d       }|j                  d#d       }|j                  d$d       }|j	                  d%&      }d }g }|d'k(  rd(}|||||	|
|||||||||||| g}n{|d)k(  rd*}||||	|
||||| g
}ng|d+k(  rd,}|||	|
||||||||||| g}nN|d-k(  rI|j                  d.| f       |j                         } | r| d$   nd }!d/}|||||	|
||||||||||||||||||!| g}|*dd	d|r|j                          |r|j                          S S |j                  ||       |j                          d0| d1}"|j                  |"| f       |j                         }#|j                          |j                          d%d2|#d3|r|j                          |r|j                          S S # t        $ r@}$dd4t        |$       dcY d }$~$|r|j                          |r|j                          S S d }$~$ww xY w# |r|j                          |r|j                          w w xY w)5NF%   Error de conexión a la base de datosr   r&    zDatos de llegada: zNombre de la tabla: )inscripciones_voluntariosunion_voluntarios_antiguosbase_datos_10kregistros_crm_antiguoprospectos_manualu-   Tabla no válida especificada en la solicitudtipo_documento	documentonombres	apellidoscorreostelefonopaisdepartamentociudad	direcciongenerorecomendadoNonombre_recomendadorzNo recomendadogrupo_wp	grupo_wp1como_ayudarpasionnombres_completos	interesesautorizacionbarriofecha_cumpleanos	localidadtipo_sangrefecha_registroTr   rK   a  
                UPDATE inscripciones_voluntarios
                SET tipo_documento = %s, documento = %s, nombres = %s, apellidos = %s, correos = %s, 
                    telefono = %s, pais = %s, departamento = %s, ciudad = %s, direccion = %s, 
                    genero = %s, recomendado = %s, nombre_recomendador = %s, grupo_wp = %s, 
                    grupo_wp1 = %s, como_ayudar = %s, pasion = %s
                WHERE id = %s
            rM   a  
              UPDATE base_datos_10k
              SET fecha_registro = %s, nombres_completos = %s, documento = %s, correos = %s, 
              telefono = %s, departamento = %s, ciudad = %s, intereses = %s, autorizacion = %s
              WHERE id = %s
          rN   av  
                UPDATE registros_crm_antiguo
                SET nombres = %s, apellidos = %s, correos = %s, telefono = %s,
                    tipo_documento = %s, documento = %s, departamento = %s, ciudad = %s, localidad = %s,
                    barrio = %s, direccion = %s, fecha_cumpleanos = %s, genero = %s, tipo_sangre = %s
                WHERE id = %s
            rO   z:SELECT fecha_registro FROM prospectos_manual WHERE id = %saK  
                UPDATE prospectos_manual
                SET nombres = %s, apellidos = %s, tipo_documento = %s, documento = %s, correos = %s, 
                    telefono = %s, pais = %s, departamento = %s, ciudad = %s, localidad = %s, 
                    barrio = %s, direccion = %s, fecha_cumpleanos = %s, genero = %s, tipo_sangre = %s, 
                    recomendado = %s, nombre_recomendador = %s, grupo_wp = %s, grupo_wp1 = %s, 
                    como_ayudar = %s, pasion = %s, intereses = %s, autorizacion = %s, fecha_registro = %s
                WHERE id = %s
            zSELECT * FROM z WHERE id = %szVoluntario actualizador   zError al actualizar los datos: )
r   r8   printr   r   r   r<   commitr   r   )%id_voluntarior   r   r   r&   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r]   r^   r_   r`   ra   rb   rc   rd   re   rf   rg   rh   ri   r    rB   resultfecha_registro_actualquery_selectvoluntario_actualizador"   s%                                        r#   actualizar_voluntario_dbrq     s   !JF -TUUKxx3"4&)*$\N34   
 
  %1`ar LLN q "2D9HH[$/	((9d+HH[$/	((9d+88J-xx%xx5(D)HH[$/	(D)hh}d3;t"hh'<dCWGW88J-HH[$/	hh}d3(D) HH%8$?HH[$/	xx5(D)88$6=HH[$/	hh}d3"2D9
 ""d"366E %i)WhL&)V[)8YVUbdF
 --E %&7GlFI|]TF 44E y'8	<	#3V[-YF 00NNWZgYij__&F@FF+;$<D!E y.)Wh,	69N^K6I8U^LBWYfhF =$1`a0 LLN + 	uf% 	 (~^D|m%56!'!2,DNde LLN   Y /NsSTvh-WXX LLN Y LLN s=   6N* 1I=N* A0N* *	O33O.O3O6 .O33O6 6'Pc           	      d   	 t               }|Addddt               v rj                          dt               v r|r|j                          S S S | j                  d      }| j                  d      }| j                  d      }| j                  d	      }| j                  d
      }| j                  d      }|dv rd }t	        d |||||fD              rAddddt               v rj                          dt               v r|r|j                          S S S |j                         }d}	|j                  |	||||||f       |j                          ddddt               v r|j                          dt               v r|r|j                          S S S # t        $ rW}
ddt        |
       dcY d }
~
dt               v rj                          dt               v rr|j                          S S S d }
~
ww xY w# dt               v rj                          dt               v rr|j                          w w w xY w)Nr   r   r   r   r   id_empleadoid_contacto_origenid_contacto_unionorigen_datosid_estado_etapanota)NrJ   	undefinednullc              3   $   K   | ]  }|d u  
 y wN ).0xs     r#   	<genexpr>zcreateNotes.<locals>.<genexpr>  s     kQqDyks   zFaltan datos requeridosz
            INSERT INTO notas_contacto (fecha_hora, id_empleado, id_contacto_origen, id_contacto_union, origen_datos, id_estado_etapa, nota)
            VALUES (NOW(), %s, %s, %s, %s, %s, %s)
        r   zNota creada correctamenter   )
r   r7   r   r8   anyr   r   rk   r   r   )r   r   r   rs   rt   ru   rv   rw   rx   r    r"   s              r#   createNotesr     s<   .#%
/P vxLLN68#
 )3#K hh}-!XX&:; HH%89xx/((#45xx=="Ok;0BDUWcei"jkk40 vxLLN68#
 )3#+ ""$ 	u{,>@QS_aprvwx 2
 vxLLN68#
 )3#  
 Q)
 	

 vxLLN68#
 )3#
 vxLLN68#
 )3#s<   F BF >F 	G.G)'G.(G1 )G..G1 1>H/c                    	 t               }|Addddt               v rj                          dt               v r|r|j                          S S S | j                  d      }|sAddddt               v rj                          dt               v r|r|j                          S S S |j	                  d	      }d
}|j                  ||f       |j                         }dd|ddt               v r|j                          dt               v r|r|j                          S S S # t        $ rW}ddt        |       dcY d }~dt               v rj                          dt               v rr|j                          S S S d }~ww xY w# dt               v rj                          dt               v rr|j                          w w w xY w)Nr   r   r   r   r   rt   zFalta el ID del contactoTr   a  
            SELECT nc.*, 
                   CONCAT(e.nombres, ' ', e.apellidos) AS nombre_empleado, 
                   ee.estado_etapa AS estado_etapa
            FROM notas_contacto nc
            JOIN empleados e ON nc.id_empleado = e.id
            LEFT JOIN estados_etapas ee ON nc.id_estado_etapa = ee.id
            WHERE nc.id_contacto_origen = %s
            ORDER BY nc.fecha_hora DESC
        r   zNotas obtenidas correctamenter   r   )	r   r7   r   r8   r   r   r   r   r   )r   r   r   rt   r    notasr"   s          r#   getNotesContactr     s   ,#%
/L vxLLN68#
 )3#G "XX&:;!5> vxLLN68#
 )3#9 ""d"3	 	u134! 6
 vxLLN68#
 )3#  
 Q)
 	

 vxLLN68#
 )3#
 vxLLN68#
 )3#s;   D D #<D 	E<%E75E<6E? 7E<<E? ?>F=r   c                 @   	 | j                  d      }| j                  d      }| j                  d      }| j                  dd       }| j                  dd      }t               }|+ddi d	r|j                          |r|j                          S S |j                  d
      }d}|j	                  |||f       |j                         }	|	r1d
d|	d   d
dd	|r|j                          |r|j                          S S d
dd ddd	|r|j                          |r|j                          S S # t        $ rA}
ddt        |
       i d	cY d }
~
r|j                          r|j                          S S d }
~
ww xY w# r|j                          r|j                          w w xY w)NrQ   rT   rU   idOrigenDatonombreTablarJ   FrI   r   Tr   z
            SELECT id
            FROM union_contactos_personas
            WHERE id_origen_datos = %s
                AND origen_datos = %s
        u&   Registro encontrado en tabla de uniónr4   )campo_encontradoexistu)   Registro no encontrado en la tabla uniónzError en la consulta: )r8   r   r   r   r   r<   Errorr   )r   rQ   rT   rU   r   r   r   r   r    	resultador"   s              r#   verificacion_persona_contactadar     s   =HH[)	((9%88J'xx5hh}b1 $%
$1Xbde^ LLN _ ""d"3 	u|[9:OO%	 C(1$!0 LLN   F(," LLN   \ /Ec!fX-NXZ[[ LLN \
 LLN s=   A(D) AD) ;D) )	E32E.E3E6 .E33E6 6'Fc                 n   	 | j                  d      }| j                  d      }| j                  d      }g d}||vr+ddi dr|j                          r|j                          S S t               }|+ddi dr|j                          |r|j                          S S |j                         }d	| d
}|j	                  |||f       |j
                  dkD  r=|j                          ddd|id|r|j                          |r|j                          S S ddi d|r|j                          |r|j                          S S # t        $ rA}ddt        |       i dcY d }~r|j                          r|j                          S S d }~ww xY w# r|j                          r|j                          w w xY w)Nrv   r2   r4   rK   rN   rM   rO   Fu#   La tabla especificada no es válidar   rI   z
            UPDATE zF 
            SET estado_etapa = %s
            WHERE id = %s
        r   Tz=Estado de la etapa del contacto actualizado a primer contactou3   No se encontró el registro con el id proporcionadou   Error en la actualización: )	r8   r   r   r   r   rowcountrk   r   r   )	r   rv   r2   id_registrorA   r   r   update_queryr"   s	            r#   "actualizar_estado_etapa_verificador   C  s   1xx/xx/hhtn
 ~-$1V`bc< LLN ; $%
$1Xbde2 LLN 3 ""$ > "	 	|lK%@A ??Q#0oz~  AL  zM  N LLN   %1fprs LLN   b /KCPQF8-T^`aa LLN b
 LLN sC   A E  (E  AE  E   	F
	FF
F F

F 'F4c                 r
   d }d }	 | j                  dd      }| j                  dd      }| j                  dd      }| j                  dd      }| j                  dd      }| j                  dd      }| j                  dd       }	| j                  d	d       }
| j                  d
d       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }| j                  dd       }g d}||vr+ddi d|r|j                          |r|j                          S S t               }|+dd i d|r|j                          |r|j                          S S |j                  d!"      }d }|r7d#j	                  |$      }|j                  ||f       |j                         rd}|s9|r7d%j	                  |$      } |j                  | |f       |j                         rd}|s9|r7d&j	                  |$      }!|j                  |!|f       |j                         rd}|r/dd'| d(i d|r|j                          |r|j                          S S |d)k(  rd*}"|	|||||||
|||||||||||f}#nV|d+k(  r| d,| }$d-}"||$||||
||||f
}#n;|d.k(  rd/}"|||||	||
||||||||f}#n"|d0k(  rd1}"|||	|||||
|||||||||||||||||f}#|j                  "#       |j                          |j                  }%|j                          |j                          d!d2d3|%id|r|j                          |r|j                          S S # t        $ r~}&t        d4t        |&              |r$t        |d5      rt        d6|j                          dd7t        |&       i dcY d }&~&|r|j                          |r|j                          S S d }&~&wt        $ rX}&t        d8t        |&              dd9t        |&       i dcY d }&~&|r|j                          |r|j                          S S d }&~&ww xY w# |r|j                          |r|j                          w w xY w):Nr   rJ   rR   rS   rQ   rT   rU   rP   rW   rX   r2   rZ   ri   rc   rd   rV   rY   r[   r]   r^   r_   r`   ra   rg   re   rf   rh   r   Fu   Tabla no válidar   rI   Tr   zI
                SELECT id FROM {tabla} WHERE documento = %s
            )r=   zG
                SELECT id FROM {tabla} WHERE correos = %s
            zH
                SELECT id FROM {tabla} WHERE telefono = %s
            zYa existe un registro con el z proporcionadorK   a  
                INSERT INTO inscripciones_voluntarios (
                    tipo_documento, documento, nombres, apellidos, correos, telefono, 
                    pais, departamento, ciudad, direccion, genero, recomendado, 
                    nombre_recomendador, grupo_wp, grupo_wp1, como_ayudar, pasion, 
                    fecha_registro, estado_etapa, fecha_estado
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())
            rM    a7  
                INSERT INTO base_datos_10k (
                    fecha_registro, nombres_completos, documento, correos, telefono, 
                    departamento, ciudad, intereses, autorizacion, estado_etapa, fecha_estado
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())
            rN   a  
                INSERT INTO registros_crm_antiguo (
                    nombres, apellidos, correos, telefono, tipo_documento, documento,
                    departamento, ciudad, localidad, barrio, direccion, fecha_cumpleanos,
                    genero, tipo_sangre, estado_etapa, fecha_estado
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())
            rO   aH  
                INSERT INTO prospectos_manual (
                    nombres, apellidos, tipo_documento, documento, correos, telefono, 
                    pais, departamento, ciudad, localidad, barrio, direccion, fecha_cumpleanos, 
                    genero, tipo_sangre, recomendado, nombre_recomendador, grupo_wp, grupo_wp1, 
                    como_ayudar, pasion, intereses, autorizacion, fecha_registro, estado_etapa, fecha_estado
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())
            zProspecto agregado exitosamenter4   zError de MySQL: 	statementu   Última consulta ejecutada: u   Error en la inserción: zError general: zError inesperado: )r8   r   r   r   formatr   r<   rk   	lastrowidr   rj   r   hasattrr   r   )'r   r   r   r   rR   rS   rQ   rT   rU   rP   rW   rX   r2   rZ   ri   rc   rd   rV   rY   r[   r]   r^   r_   r`   ra   rg   re   rf   rh   rA   campo_duplicadoquery_verificar_documentoquery_verificar_correosquery_verificar_telefonoquery_insertvaloresrb   id_insertador"   s'                                          r#   agregar_prospecto_nuevor   x  s   JFphh}b1((9b)HH["-	HH["-	((9b)88J+"2D9xx5(D)xx5(D)"2D9HH[$/	xx5xx%HH[$/	hh}d3"hh'<dC88J-HH[$/	hh}d3(D)HH[$/	(D)88$6=hh}d3
 n,$1CRPP LLN O $%
$1XbdeF LLN G ""d"3  )[) & NN4ylC "-7'[) $ NN2WJ? "+8([) % NN3h[A ",$3PQ`Paao1pz|}B LLN A 55L 	7IwlFI%8)[G ,,#*)1YK 8L  19gxfiG 33L GX~yfi+V\	G //L NIwlFIvyJZ[2ExQZVYnl	G 	|W- '' 	 8<(
& LLN   ^ Q)*gfk201A1A0BCD /GAx-PZ\]] LLN   XAx() /A#a&-JTVWW LLN X LLN s]   G!P& P& CP& 8CP& &	T/AR(=T>T (T4(TTT TT 'T6archivoprocesamiento_ligeroreturnc                 :  K   h d}| j                   xs dj                         }| j                  xs d}|r	 | j                  j	                  d       |j                  d      s||v r(t        j                  | j                  dt        d      }n(t        j                  | j                  t        ddd	      }	 | j                  j	                  d       |S | j                          d{   }	 | j                  j	                  d       |j                  d      s||v r%t        j                  t        |      dt        
      S t        j                  t        |      t        dd      S # t
        $ r Y #w xY w# t
        $ r Y |S w xY w7 # t
        $ r Y w xY ww)u5  
    Convierte un UploadFile (Excel o CSV) en un DataFrame de pandas.
    - Si procesamiento_ligero=True → sólo lee las primeras 15 filas (rápido) 
      y deja el puntero en 0 para poder volver a procesar el archivo completo después.
    - Si procesamiento_ligero=False → lee el archivo completo.
    >   application/vnd.ms-excel.application/vnd.ms-excel.sheet.macroEnabled.12Aapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetrJ   r   )z.xlsxz.xlsz.xlsmz.xlsb   )
sheet_namedtypenrowsNpython)r   sepenginer   )r   r   )r   r   r   )filenamelowercontent_typefileseekr   endswithpd
read_excelr   read_csvreadr   )r   r   TIPOS_EXCELnombre_archivotipo_contenidodfraws          r#   archivo_a_dataframer   .  sp    K &&,"335N))/RN	LLa  ""#FG>]hKhw||BOBW\\$xWYZB	LLa  	 LLN"	LLa  ""#FG>]hKh==!3GG;;ws|3DRR3  		  			 #  		s~   5FE* A%F9E: F)F
*F/F 
A F*	E73F6E77F:	FFFF	FFFFexcelc                 r   K   t        | d       d {   }|ddi dS t        |      sdddS dddS 7 !w)	NTr   FError al leer el archivor   u$   Encabezados inválidos en el archivor   u   Encabezados válidos)r   validar_headers_en_primera_fila)r   r   s     r#   1procesamiento_principal_paso_1_validacion_formator   ]  sO     "5tD	DB	z -GQSTT*2. -STT,BCC 
Es   75"7c                    K   t        | d       d {   }|ddi dS t        |      }t        |      dk(  rdddg idS dd	d|idS 7 5w)
NTr   Fr   r   r   z(No se encontraron columnas en el archivocolumnaszColumnas obtenidas)r   obtener_columnas_dfr'   )r   r   r   s      r#   5procesamiento_principal_paso_2_obtener_columnas_excelr   h  sn     "5tD	DB	z -GQSTT"2&H
8} -Wblnpaqrr(<zS[F\]] 
Es   AA	6Ac                     K   t               S wr|   )/obtener_columnas_obligatorias_prospectos_manualr}       r#   Jprocesamiento_principal_paso_3_obtener_columnas_obligatorias_base_de_datosr   q  s     :<<   c                     K   t               S wr|   )-obtener_columnas_opcionales_prospectos_manualr}   r   r#   Hprocesamiento_principal_paso_4_obtener_columnas_opcionales_base_de_datosr   u  s     8::r   c                 j   K   t        | d       d {   }t        |d       d {   }|S 7 7 w)NTr   <   )timeout_seconds)r   validar_datos_con_openai)r   r   respuesta_openais      r#   0procesamiento_principal_paso_5_validacion_openair   x  s5     "5tD	DB5b"MM 
EMs   3/3133mapeo_columnasc           	        K   t        d       t        d|        t        |        d {   }|t        d       ddi dS 	 t        dt        |       dt        |j                         d	       t        d
t	        |j                                |j                         D cg c]  }||j                  vs| }}|r-t        d|        dd| |t	        |j                        ddS t        d       t        |j                         |      }t        dt	        |j                                t        d       t        |j                               }t        dt	        |j                                t        d       t        |j                               }t        dt	        |j                                t        d       t        |j                               }t        dt	        |j                                t        d       t        |j                               }	t        dt	        |	j                                t        d       d|j                  d      j                  d      j                  d      |j                  d      j                  d      j                  d      |j                  d      j                  d      j                  d      |j                  d      j                  d      j                  d      |j                  d      j                  d      j                  d      |	j                  d      j                  d      j                  d      ddS 7 Hc c}w # t        $ r:}
t        d        d!d l}|j#                          t%        d"t'        |
      #      d }
~
ww xY ww)$Nz=== Paso 6: Inicio ===u   📌 Mapeo Columnas recibido: u#   ❌ Error: no se pudo leer el ExcelFr   r   u   ✅ DataFrame leído con z	 filas y z	 columnasu$   📋 Columnas originales del Excel: u   ⚠️ Columnas faltantes: z"Columnas no encontradas en Excel: )	faltantescolumns_excelu#   👉 Aplicando mapeo_de_columnas...u    ✅ df_mapeado listo. Columnas: u2   👉 Aplicando incluir_solo_columnas_necesarias...u0   ✅ df_con_columnas_necesarias listo. Columnas: u2   👉 Aplicando normalizar_columnas_obligatorias...u.   ✅ df_columnas_obligatorias listo. Columnas: u0   👉 Aplicando normalizar_columnas_opcionales...u,   ✅ df_columnas_opcionales listo. Columnas: u+   👉 Aplicando categorizacion_prospectos...u%   ✅ df_categorizado listo. Columnas: z(=== Paso 6: Finalizado correctamente ===T   rJ   recordsorient)dataframe_originaldataframe_mapeado!dataframe_con_columnas_necesariasdataframe_columnas_obligatoriasdataframe_columnas_opcionalesdataframe_categorizado)r   r   u   ❌ ERROR en Paso 6:r   i  )status_codedetail)rj   r   r'   columnslistkeysmapeo_de_columnascopy incluir_solo_columnas_necesarias normalizar_columnas_obligatoriasnormalizar_columnas_opcionalescategorizacion_prospectosheadfillnato_dictr   	traceback	print_excr   r   )r   r   r   colr   
df_mapeadodf_con_columnas_necesariasdf_columnas_obligatoriasdf_columnas_opcionalesdf_categorizador"   r   s               r#   Hprocesamiento_principal_paso_6_procesar_excel_y_guardar_en_base_de_datosr   ~  sg     

"#	*>*:
;<"5)	)B	z34 -GQSTT5<)#b')C

O;LIVW4T"**5E4FGH %3$7$7$9SSS

=RSS	S/	{;< ?	{K&/$rzzBRS  	34&rwwy.A
0j6H6H1I0JKLBC%EjooFW%X"@F`FhFhAi@jklBC#CD^DcDcDe#f >tD\DdDd?e>fgh@A!?@X@]@]@_!`<TBXB`B`=a<bcd;<34J4O4O4QR5d?;R;R6S5TUV89 &(ggaj&7&7&;&C&C9&C&U%/__Q%7%>%>r%B%J%JR[%J%\5O5T5TUV5W5^5^_a5b5j5jr{5j5|3K3P3PQR3S3Z3Z[]3^3f3fnw3f3x1G1L1LQ1O1V1VWY1Z1b1bjs1b1t*9*>*>q*A*H*H*L*T*T\e*T*f

 
	
U 
* TX  <$%CF;;	<sY   (O M2O A!M: $M58M5<0M: ,O -JM: 1O 5M: :	N=5N88N==O r   c                     | j                   D cg c])  }t        |      j                         j                         + }}|D cg c]  }|s|j	                  d      r| }}t        |      dkD  S c c}w c c}w )u   
    Valida que en la primera fila (header=0) existan encabezados reales.
    Retorna True si hay al menos un header válido distinto de 'Unnamed', False si no.
    unnamedr   )r   r   stripr   
startswithr'   )r   cr   headers_validoss       r#   r   r     sf    
 13

;1A$$&;H;"*PQaY8OqPOP!## <Ps   .A1A6A6A6c                      t               } | ddi dS | j                  d      }|j                  d       |j                         }dd|D cg c]  }|d   d	k7  s|d    c}dS c c}w )
NFrI   r   Tr   zbSELECT columna FROM columnas_obligatorias where es_obligatoria = 1 AND tabla = 'prospectos_manual'zColumnas obligatorias obtenidascolumnar4   r   r   r   r   )r   r   columnas_obligatoriasr  s       r#   r   r     s    #%
$1Xbdee""d"3{| & 1,M  oD  X]ij  HI  JS  HT  X\  H\XYZcXd  X]  ^  	^  X]   A&A&c                      t               } | ddi dS | j                  d      }|j                  d       |j                         }dd|D cg c]  }|d   d	k7  s|d    c}dS c c}w )
NFrI   r   Tr   zKSELECT columna FROM columnas_obligatorias WHERE tabla = 'prospectos_manual'zTodas las columnas obtenidasr  r4   r  )r   r   r   r  s       r#   ,obtener_todas_las_columnas_prospectos_manualr	    s    #%
$1Xbdee""d"3de//#,Jks  UMfgwx  zC  xD  HL  xLUVW`Ua  UM  N  	N  UMr  c                      t               } | ddi dS | j                  d      }|j                  d       |j                         }dd|D cg c]  }|d   d	k7  s|d    c}dS c c}w )
NFrI   r   Tr   zbSELECT columna FROM columnas_obligatorias where es_obligatoria = 0 AND tabla = 'prospectos_manual'zColumnas opcionales obtenidasr  r4   r  )r   r   columnas_opcionalesr  s       r#   r   r     s    #%
$1Xbdee""d"3{|$oo/,Kl  VYgh  DE  FO  DP  TX  DXVWXaVb  VY  Z  	Z  VYr  c                     | j                   j                         D cg c]  }t        |      j                          c}S c c}w r|   )r   tolistr   r   )r   r  s     r#   r   r     s-    $&JJ$5$5$78qCFLLN888s    A c                     | j                  d      j                         }|j                  d      }|j                  d      }|S )u{   
    Retorna una lista de hasta 10 diccionarios con las primeras filas del DataFrame,
    limpiando NaN/None a vacío.
    
   rJ   r   r   )r   r   r   r   )r   
df_muestralista_diccionarioss      r#   obtener_primeras_10_filas_dfr    sH     !!#J ""2&J $++9+=r   openai_api_keymodelr   c                   K   t               }t        t        |             }d| d| d}|xs t        j                  d      xs dj                         j                  d      j                  d      }t        d|rd	nd
        t        d|        |sdddS d}d| dd}	|dddd|dgdd}
t        d|        d}	 t        j                  |      4 d{   }|j                  ||	|
       d{   }|j                          |j                         }t        d|        |j                  di g      d   j                  di       j                  d d      xs d}t        |       ddd      d{    |j                         j                         }||d"k(  d#S 7 7 7 .# 1 d{  7  sw Y   >xY w# t        $ r}t        d!|        d}Y d}~_d}~ww xY ww)$u   
    Recibe un DataFrame, extrae columnas y primeras 10 filas como string,
    envía a OpenAI y retorna:
      {
        "ai_validation": "exitosamenteexitoso" | "fracasadamentefracasado",
        "valid": bool
      }
    u   
Eres un validador de coherencia de datos tabulares. 
Tu tarea es revisar si las columnas especificadas tienen sentido lógico y son consistentes.

COLUMNAS A VALIDAR:
zF

MUESTRA DE DATOS (Es una lista de diccionarios que mapea la tabla):
u  

Criterios de validación:
- Documento: puede ser cédula, tarjeta de identidad, pasaporte, NIT u otro identificador. 
  Debe parecer razonable (dígitos o combinación alfanumérica típica de documentos), 
  no palabras incoherentes como "ABCXYZ" o "123hola".
- Nombres: deben contener letras, no solo números ni símbolos raros.
- En general: se considera coherente si al menos el 60% de los campos de las columnas especificadas tienen sentido. 
  No es necesario que todos estén correctos, basta con mayoría razonable.
- Los datos nulos no son considerados incoherentes.

Reglas de salida:
1. Si las filas cumplen con al menos un 50% de coherencia en las columnas especificadas → responde ÚNICAMENTE: exitosamenteexitoso
2. Si alguna fila cae por debajo del 50% de coherencia en las columnas especificadas → responde ÚNICAMENTE: fracasadamentefracasado

No des explicaciones, no repitas las filas. Responde SOLO con la palabra clave fracasadamentefracasado o exitosamenteexitoso.
OPENAI_API_KEYrJ   "'zUsando API Key: u   sínoz	Api Key: fracasadamentefracasadoF)ai_validationvalidz*https://api.openai.com/v1/chat/completionszBearer zapplication/json)AuthorizationzContent-Typesystemz5Eres un verificador de coherencia de datos tabulares.)rolecontentuserr   )r  messagestemperaturezprompt: )timeoutN)headersjsonzdata: choicesr   r   zError en la llamada a OpenAI: exitosamenteexitoso)r  r   )r   r   r  osgetenvr   rj   httpxAsyncClientpostraise_for_statusr&  r8   r   r   )r   r  r  r   r   filas_textopromptapi_keyurlr%  payloadai_textclientrespr   r"   s                   r#   r   r     s!     ?@H2267K
 

   F6 B+;!<BIIKQQRUV\\]`aG	gU48
9:	IgY
 !:UKK
6C")' 3EWXG*ab/
 G 
HVH
G,$$_= 
	 
	S'HHD!!#99;DF4&/"RD)!,SB'SB'+ +	 
 'N
	 
	 mmo##%G !33 #
	H
	 
	 
	 
	  ,.qc23+,s   C G(G F'G !F-9F):A7F-1G <F+=G &G('G )F-+G -F?3F64F?;G 	G%G G( G%%G(mapeoc                 *    | j                  |      } | S )zS
    Mapea los nombres de las columnas del DataFrame a nombres estandarizados.
    )r   )rename)r   r7  s     r#   r   r   V  s     
5	!BIr   c                     t               j                  dg       }t        d|        |D ]  }|| j                  vsd| |<    | |   j	                         } | S )a  
    Ajusta el DataFrame para que tenga exactamente las columnas de la tabla prospectos_manual:
    - Agrega las que falten (rellenadas con None).
    - Elimina las que no corresponden.
    - Devuelve el DataFrame con las columnas en el orden correcto.
    r   zColumnas tabla: N)r	  r8   rj   r   r   )r   columnas_tablar   s      r#   r   r   ]  sj     BCGGPRSN	^,
-. bjj BsG 
N		 	 	"BIr   c                    dt         dt         fd}dt         dt         fd}dt         dt         fd}dt         dt         fd}d| j                  v r| d   j                  |      | d<   d| j                  v r| d   j                  |      | d<   d	| j                  v r| d	   j                  |      | d	<   d
| j                  v r| d
   j                  |      | d
<   d| j                  v r| d   j                  |      | d<   | S )u  
    Normaliza las columnas obligatorias del DataFrame según reglas:
    - nombres, apellidos: minúsculas, sin espacios extra.
    - documento: solo dígitos.
    - correos: debe contener '@'.
    - telefono: solo dígitos, espacios y '+'.
    
    Diferencia entre:
      - "no ingresado": cuando está vacío o nulo.
      - "mal digitado": cuando hay datos pero no cumplen reglas.
    Todo se retorna en minúscula.
    valorr   c                     | r1t        j                  |       st        |       j                         dk(  ryt        |       j                         j	                         S )NrJ   no ingresador   isnar   r   r   r=  s    r#   limpiar_textoz7normalizar_columnas_obligatorias.<locals>.limpiar_texto|  sB    #e**:*:*<*B!5z!''))r   c                     | r1t        j                  |       st        |       j                         dk(  ryt	        j
                  ddt        |             }|r|S dS )NrJ   r?  z\Dmal digitado)r   rA  r   r   resub)r=  solo_numeross     r#   limpiar_documentoz;normalizar_columnas_obligatorias.<locals>.limpiar_documento  sI    #e**:*:*<*B!vveRU4+|??r   c                     | r1t        j                  |       st        |       j                         dk(  ryt        |       j                         j	                         }d|v r|S dS )NrJ   r?  @rE  r@  )r=  correos     r#   limpiar_correoz8normalizar_columnas_obligatorias.<locals>.limpiar_correo  sR    #e**:*:*<*B!U!!#))+v:N:r   c                 
   | r1t        j                  |       st        |       j                         dk(  ryt	        j
                  ddt        |             }|j                         r|j                         j                         S dS )NrJ   r?  z[^0-9 +]rE  )r   rA  r   r   rF  rG  r   )r=  rU   s     r#   limpiar_telefonoz:normalizar_columnas_obligatorias.<locals>.limpiar_telefono  s`    #e**:*:*<*B!66+r3u:6+3>>+;x~~%%'OOr   rR   rS   rQ   rT   rU   )r   r   apply)r   rC  rI  rM  rO  s        r#   r   r   n  s   *S *S *
@ @ @;c ;c ;P P P BJJ9++M:9bjj [///>;bjj [///0AB;BJJ9++N;9RZZJ--.>?:Ir   c                     t               j                  dg       }dt        dt        fd}|D ](  }|| j                  v s| |   j	                  |      | |<   * | S )u   
    Normaliza las columnas opcionales del DataFrame:
    - Convierte a minúsculas y elimina espacios extra.
    - Si está vacío o solo contiene espacios → "no digitado".
    r   r=  r   c                     | r1t        j                  |       st        |       j                         dk(  ryt        |       j                         j	                         S )NrJ   zno digitador@  rB  s    r#   limpiar_opcionalz8normalizar_columnas_opcionales.<locals>.limpiar_opcional  sB    #e**:*:*<*B 5z!''))r   )r   r8   r   r   rP  )r   r  rS  r   s       r#   r   r     sj     HIMMfVXY* * *
 # 6"**gmm$45BsG6 Ir   c                 ^   dt         dt        fd}g }| j                         D ]r  \  }} ||j                  dd            } ||j                  dd            }|r|r|j	                  d       L|s|r|j	                  d       b|j	                  d	       t | j                         } || d
<   | S )u+  
    Agrega una columna 'categoria_prospecto' según la disponibilidad de contacto:
      - 'total'     → correo y teléfono válidos
      - 'parcial'   → al menos uno válido
      - 'descartado'→ ninguno válido
    Se consideran inválidos los valores 'no ingresado' o 'mal digitado'.
    r=  r   c                     | rt        j                  |       ryt        |       j                         j	                         } | dvS )NF)r?  rE  r@  rB  s    r#   	es_validoz,categorizacion_prospectos.<locals>.es_valido  s9    E
  "((*<<<r   rT   NrU   r0   parcial
descartadocategoria_prospecto)r   booliterrowsr8   r:   r   )r   rV  
categorias_fila	correo_oktelefono_oks          r#   r   r     s    = = = J;;= 	,4dhhy$78	T :;g&+i(l+	, 
B *BIr   c                    | j                   ryt        | j                        }dj                  d |D              }dj                  dgt	        |      z        }d| d| d| d}| j                  d	d
      D cg c]  }t        |       }}t               }	|	j                         }
d}	 t        dt	        |      |      D ]*  }||||z    }|
j                  ||       |t	        |      z  }, |	j                          ||
j                          |	j                          S c c}w # t        $ r |	j                           w xY w# |
j                          |	j                          w xY w)zi
    Inserta un DataFrame en MySQL por lotes (chunks).
    Devuelve la cantidad de filas insertadas.
    r   z, c              3   (   K   | ]
  }d | d   yw)`Nr}   )r~   r  s     r#   r   z-insercion_masiva_dataframe.<locals>.<genexpr>  s     8!q1X8s   z%szINSERT INTO `z` (z
) VALUES ()FN)indexname)emptyr   r   joinr'   
itertuplesr;   r   r   rangeexecutemanyrk   r   r   rollback)r   r&   tamano_loter   columnas_sqlplaceholders
insert_sqlr^  datosconncur
insertadosilotes                 r#   insercion_masiva_dataframerw    sK   
 
xx BJJH998x88L99dVc(m34L c,z,WXYJ &(]]T]%JKTU4[KEKD
++-CJq#e*k2 	$A1[=)DOOJ-#d)#J	$
 	
 			

' L   			

s   :D +AD% %E  E "E%c                    ddddd}| | d   dk(     j                         }|j                  sd|d<   g d}t        ||   d	      |d
<   | | d   dk(     j                         }|j                  sd|d<   g d}t        ||   d	      |d<   | | d   dk(     j                         }|j                  sg d}t        ||   d      |d<   d|d<   |S )u   
    Inserta los prospectos en sus tablas correspondientes:
    - total/parcial → prospectos_manual
    - descartado → descartados_contactabilidad
    Devuelve un resumen con cuántos se insertaron en cada lugar.
    Fr   )r   prospectos_manual_totalprospectos_manual_parcialdescartados_contactabilidadrY  r0   r   validacion_contactabilidad)rR   rS   rP   rQ   rT   rU   rV   rW   rX   rg   re   rY   rf   rZ   rh   r[   r]   r^   r_   r`   ra   rc   rd   ri   r2   fecha_estador|  rO   ry  rW  r   rz  rX  )rR   rS   rP   rQ   rT   rU   rV   rW   rX   rg   re   rY   rf   rZ   rh   r[   r]   r^   r_   r`   ra   rc   rd   ri   r2   r}  r{  Tr   )r   rg  rw  )r   resumendf_totalcolumnas_prospectos
df_parcialdf_desccolumnas_descartadoss          r#   insertar_prospectosr    s&    #$%&'(	G "*+w67<<>H>>12-.
 .HQdHegz-{)* B,-:;@@BJ34
/0
 0J*UhJik~/+, )*l:;@@BG== 
 2LGThLi  lI  2J-.GINr   )F)Nzgpt-4o-mini   )i  )=http.clientr   sysr)  r   typingr   fastapir   pandasr   ior   rF  r+  r   r	   r
   dotenvr   r   pathr:   cnxpdor   r$   r+   rG   rq   r   r   dictr   r   r   rZ  	DataFramer   r   r   r   r   r   r   r   r   r   r	  r   r   r   r  r9   r   r   r   r   r   r   rw  r  r}   r   r#   <module>r     s   % 
 	      	  , ,   
 & ' !
8
\bHRl/d-b>$ >D2T 2js$ sl-Sz -S -SZ\ZfZf -S^	D: 	DRVWZ\_W_R` 	D^z ^=;* A<A<cNA< 
#s(^A<D$ $ $^NZ9BLL 9T#Y 9
R\\ d4j $ %)	R
RSMR R 	R
 
#s(^Rn",, tCH~ ",,  ",, "1 1",, 1hr||  &",, 2<< @"H4r   