U
    iw                     @   s<  d dl Z d dlZd dlmZ d dlmZmZmZmZ edZ	d dl
mZmZ d dlmZ dd Zeee d	d
dZeee d	ddZeeeedddZeeeedddZeee edddZeeeeedddZeedddZeedddZd d! Zeed"d#d$Zeedd%d&Zeeed'd(d)Z dS )*    N)datetime)DictListOptionalUnionZcotizaciones_especiales_sql)
ProductivoENVIRONMENT)get_connectionc           
      C   s0  d}d| ||ddf}d}d}zzht }|s4W W dS | }||| | }|  |r~|d }td|  |W W nS W W fdS  tk
r }	 z@t	dt
|	  |rz|  W n   Y nX W Y W dS d}	~	X Y nX W 5 |r
z|   W n   Y nX |r*z|   W n   Y nX X dS )u  
    Inserta un registro en Q_CRM usando solo:
    - contactName
    - contactNumber
    - contactEmail

    Y devuelve el nuevo CRM_OpportunityNumber (identity).

    Returns:
        Optional[int]: Nuevo OpportunityNumber si se insertó, None si hubo error.
    aQ  
        INSERT INTO Q_CRM (
            CRM_Version,
            CRM_ContactName,
            CRM_ContactNumber,
            CRM_ContactEmail,
            Status,
            CreatedAt,
            CreatedBy,
            Active
        )
        OUTPUT INSERTED.CRM_OpportunityNumber
        VALUES (?, ?, ?, ?, ?, GETDATE(), ?, 1)
       ZSYSTEMNr   u-   ✅ CRM Contact insertado: OpportunityNumber=u$   ❌ Error al insertar contacto CRM: )closer	   cursorexecutefetchonecommitloggerinfo	Exceptionerrorstrrollback)
contactNamecontactNumbercontactEmailqueryparamsconnr   rowopportunity_numbere r   nC:\Users\victor.barrera\Documents\proyectos\elepV3\Elep\src\Consultas_SQL\Ventas\Cotiz\CotizEspSolicitudSQL.pyinsert_CRM_CONTACT   sR    	


 r!   )r   returnc           	      C   s  t d|   d}t d|   t d|  d}zzt }|sJtd| | }||| f dd |jD }| }|rtt	||}t
d|  d	 d
|kr|d
 r|d
  |d
< |W  5 Q R  W W S t
d|  d W 5 Q R  W W dS W 5 Q R X W n tjk
rX } z*d|  dt| }t
| t|W 5 d}~X Y n tk
r } z*d|  dt| }t
| t|W 5 d}~X Y nJ tk
r } z*d|  dt| }t
| t|W 5 d}~X Y nX W 5 |rz|  W n   Y nX X dS )u  
    Busca una oportunidad en la tabla Q_OpportunityCRM
    
    Args:
        opportunity_number (float): Número de oportunidad del CRM
    
    Returns:
        Dict: Diccionario con los datos de la oportunidad si se encuentra, None si no existe
        
    Raises:
        ConnectionError: Si no se puede establecer conexión con la base de datos
        Exception: Para otros errores de base de datos
    u%   🔍 DEBUG - Buscar oportunidad CRM: a<  
        SELECT TOP 1
            Q_CRM.CRM_OpportunityNumber,
            Q_CRM.CRM_Version,
            Q_CRM.CRM_ContactID,
            Q_CRM.CRM_ContactName,
            Q_CRM.CRM_ContactType,
            Q_CRM.CRM_AssignedSalesperson,
            Q_CRM.CRM_ContactAdress,
            Q_CRM.CRM_ContactColonia,
            Q_CRM.CRM_ContactCity,
            Q_CRM.CRM_ContactNumber,
            Q_CRM.CRM_ContactCountry,
            Q_CRM.CRM_ContactLegalIdentifier,
            Q_CRM.CRM_ContactZip,
            Q_CRM.CRM_ContactState,
            Q_CRM.CRM_ContactEmail,
            Q_CRM.Status,
            Q_CRM.CreatedAt,
            Q_CRM.CreatedBy,
            Q_CRM.Active
        FROM Q_CRM
        WHERE Q_CRM.CRM_OpportunityNumber = ?
            AND Q_CRM.Active = 1
        ORDER BY Q_CRM.CRM_Version DESC
    u   🔍 DEBUG - Query: N4   No se pudo establecer conexión con la base de datosc                 S   s   g | ]}|d  qS r   r   .0columnr   r   r    
<listcomp>   s     z*buscar_oportunidad_crm.<locals>.<listcomp>Oportunidad z encontrada exitosamente	CreatedAtz" no encontrada en la base de datosz-Error de base de datos al buscar oportunidad : u)   Error de conexión al buscar oportunidad z'Error inesperado al buscar oportunidad )printr   r	   ConnectionErrorr   r   descriptionr   dictzipr   r   	isoformatwarningpyodbcErrorr   r   r   )	r   r   r   r   columnsr   resultr   	error_msgr   r   r    buscar_oportunidad_crmf   sN    "


r8   c           
      C   s&  d}d}zz2t }|s"td| | }||| f dd |jD }| }|rtt||}|	dd
 }|dkrtd	|  d
| d td| |dkrtd	|  d
| d td| td	|  d|d  d|  |W  5 Q R  W W S td	|  d W 5 Q R  W W dS W 5 Q R X W n tk
rh } z|W 5 d}~X Y n tjk
r } z*d|  dt| }	t|	 t|	W 5 d}~X Y nJ tk
r } z*d|  dt| }	t|	 t|	W 5 d}~X Y nX W 5 |r z|   W n   Y nX X dS )u  
    Verifica si ya existe una oportunidad y retorna la versión más alta
    También valida que no esté cerrada/vendida o en proceso activo
    
    Args:
        opportunity_number (str): Número de oportunidad del CRM
    
    Returns:
        Dict: Datos de la oportunidad existente con versión más alta, None si no existe
        
    Raises:
        Exception: Si la oportunidad está cerrada/vendida o en proceso activo
    a  
        SELECT TOP 1
            Q_OpportunityCRM.CRM_OpportunityNumber,
            Q_OpportunityCRM.Version,
            Q_OpportunityCRM.CRM_OpportunityID,
            Q_OpportunityCRM.Status,
            Q_OpportunityCRM.Active
        FROM Q_OpportunityCRM
        WHERE Q_OpportunityCRM.CRM_OpportunityNumber = ?
            AND Q_OpportunityCRM.Active = 1
        ORDER BY Q_OpportunityCRM.Version DESC
    Nr#   c                 S   s   g | ]}|d  qS r$   r   r%   r   r   r    r(      s     z3verificar_oportunidad_existente.<locals>.<listcomp>Status )ZVENDIDOZVENDIDAZATENDIDOr)   z tiene status z - proceso terminadozOPPORTUNITY_CLOSED:)	PENDIENTEzEN DESARROLLOzEN APROBACIONZEN_DESARROLLOZEN_APROBACIONz - proceso activozOPPORTUNITY_IN_PROCESS:u    encontrada con versión Versionz
 y status z no encontradaz0Error de base de datos al verificar oportunidad r+   z*Error inesperado al verificar oportunidad )r   r	   r-   r   r   r.   r   r/   r0   getupperr   r2   
ValueErrorr   r3   r4   r   r   r   )
r   r   r   r   r5   r   r6   statusr   r7   r   r   r    verificar_oportunidad_existente   sN     "

rA   )datos_oportunidaduser_idversionr"   c           
      C   s   t |}d}d}zƐzt }|s*td| | }||| dd||| dd| dd| dd| d	d| d
d| dd| dd| dd| dd| dd| dd| dd| ddd||f |  | d d| }t	d| d d|dW  5 Q R  W W S Q R X W n t
jk
r } z4dt| }	t|	 dddddd W Y W fS d}~X Y nT tk
r } z4d t| }	t|	 dd!d"ddd W Y W S d}~X Y nX W 5 |rz|  W n   Y nX X dS )#u  
    Crea o actualiza un registro en Q_OpportunityCRM
    
    Args:
        datos_oportunidad (Dict): Datos de la oportunidad
        user_id (int): ID del usuario
        version (int): Versión de la oportunidad
    
    Returns:
        Dict: Resultado de la operación
    a  
        INSERT INTO Q_OpportunityCRM (
            CRM_OpportunityNumber,
            Version,
            UserID,
            CRM_ContactID,
            CRM_ContactName,
            CRM_ContactType,
            CRM_AssignedSalesperson,
            CRM_ContactAdress,
            CRM_ContactColonia,
            CRM_ContactCity,
            CRM_ContactNumber,
            CRM_ContactCountry,
            CRM_ContactLegalIdentifier,
            CRM_ContactZip,
            CRM_ContactState,
            CRM_ContactEmail,
            Status,
            CreatedBy,
            UpdatedBy
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    Nr#   CRM_OpportunityNumberr:   CRM_ContactIDCRM_ContactNameCRM_ContactTypeCRM_AssignedSalespersonCRM_ContactAdressCRM_ContactColoniaCRM_ContactCityCRM_ContactNumberCRM_ContactCountryCRM_ContactLegalIdentifierCRM_ContactZipCRM_ContactStateCRM_ContactEmailr;   -r)   z creada exitosamenteT)successopportunity_idz-Error de base de datos al crear oportunidad: Fz,Error al guardar los datos de la oportunidadDATABASE_ERRORr   i  )rT   messagecode
alert_typestatus_codez'Error inesperado al crear oportunidad: z(Error interno al procesar la oportunidadINTERNAL_ERROR)obtener_nombre_usuarior   r	   r-   r   r   r=   r   r   r   r3   r4   r   r   r   )
rB   rC   rD   	user_namer   r   r   rU   r   r7   r   r   r    crear_actualizar_oportunidad$  sv    













"

$	r^   )rU   quotation_type_idrC   r"   c           
      C   sf  t |}d}d}z,zt }|s(td|d | }||| ||||f |  |  d| }td| d d|dW  5 Q R  W W S Q R X W n t	j
k
r } z2d	t| }	t|	 d
dddd W Y W dS d}~X Y nR tk
r: } z2dt| }	t|	 d
dddd W Y W S d}~X Y nX W 5 |r`z|  W n   Y nX X dS )u  
    Crea un registro en Q_SpQ_FormsHead
    
    Args:
        opportunity_id (str): ID de la oportunidad
        quotation_type_id (str): ID del tipo de cotización
        user_id (int): ID del usuario
    
    Returns:
        Dict: Resultado de la operación
    z
        INSERT INTO Q_SpQ_FormsHead (
            CRM_OpportunityID,
            QuotationTypeID,
            UserID,
            CreatedBy,
            UpdatedBy
        ) VALUES (?, ?, ?, ?, ?)
    Nr#   rS   z	FormHead z creado exitosamenteT)rT   form_idz*Error de base de datos al crear FormHead: Fz%Error al crear registro de formulariorV   r   rT   rW   rX   rY   z$Error inesperado al crear FormHead: z!Error interno al crear formularior[   )r\   r   r	   r-   r   r   r   r   r   r3   r4   r   r   r   )
rU   r_   rC   r]   r   r   r   r`   r   r7   r   r   r    crear_formulario_head  sV    
"

$rb   )r`   	preguntasr"   c                 C   s  t d|   t dt|  t|D ] \}}t d|d  d|  q(d}d}zz>t }|sltdd	}| | }t|dd
D ]\}}t|d}	t d| d t d|   t d|	  t d|d   t d|d   t d|d   t d|  d|	  |	|| |	|d |d |d f |d7 }t d| d q|
  td| d|   d|dW  5 Q R  W W S Q R X W n tjk
r }
 z@dt|
 }t| t d|  d d!d"d#d$ W Y W rS d}
~
X Y n` tk
rV }
 z@d%t|
 }t| t d&|  d d'd(d#d$ W Y W S d}
~
X Y nX W 5 |r|z|  W n   Y nX X dS ))u   
    Crea múltiples registros en Q_SpQ_FormsDetail
    
    Args:
        form_id (str): ID del formulario
        preguntas (List[Dict]): Lista de preguntas y respuestas
    
    Returns:
        Dict: Resultado de la operación
    u   🔍 DEBUG - FormID: u   🔍 DEBUG - Total preguntas: u   🔍 DEBUG - Pregunta r
   r+   z
        INSERT INTO Q_SpQ_FormsDetail (
            FormID,
            FormLine,
            Question,
            TypeQuestion,
            Answer
        ) VALUES (?, ?, ?, ?, ?)
    Nr#   r   )start   u!   🔍 DEBUG - Insertando registro :z    FormID: z    FormLine: z    Question: preguntaz    TypeQuestion: ZtipoElementoz    Answer: 	respuestaz    Expected FormLineID: rS   u   ✅ DEBUG - Registro z insertado exitosamentezCreados z detalles para FormID T)rT   Zrecords_createdz-Error de base de datos al crear FormDetails: u   ❌ DEBUG - Error SQL: Fz(Error al guardar detalles del formulariorV   r   ra   z'Error inesperado al crear FormDetails: u   ❌ DEBUG - Error general: z!Error interno al guardar detallesr[   )r,   len	enumerater   r	   r-   r   r   zfillr   r   r   r   r3   r4   r   r   )r`   rc   irg   r   r   Zregistros_creadosr   indexZ	form_liner   r7   r   r   r    crear_formulario_details  sv    
"

$rn   )seller_user_idr`   rU   r]   r"   c           
      C   sj  d}d}z8zt }|s td|p | }||| |d||f |d | d }|  td| d|  d	|d
W  5 Q R  W W S Q R X W n t	j
k
r } z2dt| }	t|	 ddddd W Y W dS d}~X Y nR tk
r> } z2dt| }	t|	 ddddd W Y W S d}~X Y nX W 5 |rdz|   W n   Y nX X dS )uB  
    Crea una tarea en Q_SpQ_QuotationTasks
    
    Args:
        seller_user_id (int): ID del vendedor
        form_id (str): ID del formulario
        opportunity_id (str): ID de la oportunidad
        user_name (str): Nombre del usuario que crea la tarea
    
    Returns:
        Dict: Resultado de la operación
    a4  
        INSERT INTO Q_SpQ_QuotationTasks (
            SellerUserID,
            FormID,
            Status,
            StatusDate,
            CRM_OpportunityID,
            UpdatedBy
        ) VALUES (?, ?, ?, CAST(SYSDATETIMEOFFSET() AT TIME ZONE 'Central America Standard Time' AS DATETIME), ?, ?)
    Nr#   zPor AsignarzSELECT @@IDENTITY AS TaskIDr   zTarea z creada para FormID T)rT   task_idz'Error de base de datos al crear tarea: Fu#   Error al crear tarea de cotizaciónrV   r   ra   z!Error inesperado al crear tarea: zError interno al crear tarear[   )r   r	   r-   r   r   r   r   r   r   r3   r4   r   r   r   )
ro   r`   rU   r]   r   r   r   rp   r   r7   r   r   r    crear_tarea_cotizacionA  sV    	
"

$rq   )rC   r"   c                 C   s.  d}d} zzt }|s(d|  W W S |~ | }||| f | }|rd|d  }| rn|nd|  W  5 Q R  W W S d|  W  5 Q R  W W dS W 5 Q R X W nP tk
r } z0t	
d|  dt|  d|   W Y W S d}~X Y nX W 5 |r(z|   W n   Y nX X dS )z
    Obtiene el nombre completo del usuario desde la tabla Profiles
    
    Args:
        user_id (int): ID del usuario
    
    Returns:
        str: Nombre completo del usuario
    a  
        SELECT 
            CONCAT(
                COALESCE(Profiles.FirstName, ''), ' ',
                COALESCE(Profiles.LastName, ''), ' ',
                COALESCE(Profiles.SecondLastName, '')
            ) AS FullName
        FROM Profiles
        WHERE Profiles.UserID = ?
            AND Profiles.UserID IN (
                SELECT Users.UserID 
                FROM Users 
                WHERE Users.Status = 'ACTIVO'
            )
    NZUsuario_ r   z#Error al obtener nombre de usuario r+   )r   r	   r   r   r   joinsplitstripr   r   r2   r   )rC   r   r   r   r   	full_namer   r   r   r    r\     s,    (*(r\   )r_   r"   c                 C   s  d}d}zPzt }|s4td|   W W ,dS | | }||| f | }|rt|d }td|  d|  |W  5 Q R  W W S td|  d W 5 Q R  W W dS W 5 Q R X W n t	j
k
r } z(td	|  d
t|  W Y W \dS d}~X Y nH tk
rV } z(td|  d
t|  W Y W dS d}~X Y nX W 5 |r|z|   W n   Y nX X dS )u   
    Consulta si un tipo de formulario debe crear tarea en Q_SpQ_QuotationTasks
    
    Args:
        quotation_type_id (str): ID del tipo de cotización
    
    Returns:
        bool: True si debe crear tarea, False si no
    z
        SELECT Q_QuotationType.CreateTask
        FROM Q_QuotationType
        WHERE Q_QuotationType.QuotationTypeID = ?
            AND Q_QuotationType.Active = 1
    Nz1No se pudo conectar para verificar CreateTask de Tr   zQuotationType z - CreateTask: z no encontradoz)Error de BD al consultar CreateTask para r+   z.Error inesperado al consultar CreateTask para )r   r	   r   r2   r   r   r   boolr   r3   r4   r   r   r   )r_   r   r   r   r   create_taskr   r   r   r    debe_crear_tarea  s8    " ry   c                 C   s   d}d}zzxt }|s W W dS |V | }||| f | }|rb|d W  5 Q R  W W nS W 5 Q R  W W \dS W 5 Q R X W nF tk
r } z(td|  dt|  W Y W dS d}~X Y nX W 5 |rz|   W n   Y nX X dS )z
    Obtiene el TaskID asociado a un FormID en Q_SpQ_QuotationTasks
    
    Args:
        form_id (str): ID del formulario
    
    Returns:
        Optional[int]: TaskID si existe, None si no
    z
        SELECT TOP 1
        Q_SpQ_QuotationTasks.FormID
        FROM Q_SpQ_QuotationTasks
        WHERE Q_SpQ_QuotationTasks.taskID = ?
    Nr   z$Error al obtener TaskID para FormID r+   )	r   r	   r   r   r   r   r   r2   r   )taskIDr   r   r   r   r   r   r   r    get_FormID_by_TaskID   s*    
" r{   )tipo_formularior"   c                 C   s(   ddddddddd	d
dd}| | dS )z
    Mapea el tipo de formulario al QuotationTypeID correspondiente
    
    Args:
        tipo_formulario (str): Tipo de formulario del frontend
    
    Returns:
        str: QuotationTypeID correspondiente
    FormGralFormSolicVisFormPTTransNacFormPTTransULFormAireFormSistCritUPSFormBess	FormSolar
FormEneCog	FormImessFormProyecEsp)GeneralSolicVis
PTTransNac	PTTransULAireSistCritUPSBessSolarEnergyCogenerationImess	ProyecEsp)r=   )r|   Zmapeo_tiposr   r   r    obtener_quotation_type_id-  s    r   c                 C   s  d}d}zzt }|s | W W S |d | }||| f | }|rn|d rnt|d W  5 Q R  W W rS | W  5 Q R  W W \S W 5 Q R X W nH tk
r } z*td|  dt	|  |  W Y W S d}~X Y nX W 5 | rz|   W n   Y nX X dS )a  
    Obtiene el SellerUserID desde la tabla Profiles
    Para vendedores directos, retorna el mismo user_id
    Para distribuidores, retorna el SellerUserID asignado
    
    Args:
        user_id (int): ID del usuario actual
    
    Returns:
        int: ID del vendedor asignado
    z
        SELECT 
            COALESCE(Profiles.SellerUserID, Profiles.UserID) AS SellerID
        FROM Profiles
        WHERE Profiles.UserID = ?
    Nr   z+Error al obtener SellerUserID para usuario r+   )
r   r	   r   r   r   intr   r   r2   r   )rC   r   r   r   r   r   r   r   r    obtener_seller_user_idH  s*    
$"r   )r`   docs_idr"   c                 C   s  d}d}zXzt }|s td| | }|||| f |j}|  |dkrtd|  d|  ddiW  5 Q R  W W S t	d	|  d
 dddW  5 Q R  W W S W 5 Q R X W n t
jk
r } z0dt| }t| dddd W Y W bS d}~X Y nP tk
r^ } z0dt| }t| dddd W Y W S d}~X Y nX W 5 |rz|   W n   Y nX X dS )u   
    Actualiza el formulario con el DocsID generado
    
    Args:
        form_id (str): ID del formulario
        docs_id (int): ID del grupo de documentos
    
    Returns:
        dict: Resultado de la operación
    zp
        UPDATE Q_SpQ_FormsHead 
        SET DocsID = ?
        WHERE FormID = ?
            AND Active = 1
    Nr#   r   zFormulario z actualizado con DocsID rT   Tu   No se encontró formulario z para actualizarFz(Formulario no encontrado para actualizar)rT   rW   z1Error de base de datos al actualizar formulario: z-Error al actualizar formulario con documentosrV   )rT   rW   rX   z+Error inesperado al actualizar formulario: z&Error interno al actualizar formularior[   )r   r	   r-   r   r   rowcountr   r   r   r2   r3   r4   r   r   r   )r`   r   r   r   r   Zrows_affectedr   r7   r   r   r    actualizar_formulario_con_docsw  sJ    &

$r   )!r3   loggingr   typingr   r   r   r   	getLoggerr   configr   r   Consultas_SQL.conexionr	   r!   floatr8   r   rA   r   r^   rb   rn   rq   r\   rw   ry   r{   r   r   r/   r   r   r   r   r    <module>   s&   
SjTmMcP87-/