a
    0ix                     @   sD  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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Unioncotizaciones_especiales_sql)
ProductivoENVIRONMENT)get_connectionc           
      C   sf  d}d| ||ddf}d}d}z zt  }|srW W |rPz|  W n   Y n0 |rnz|  W n   Y n0 dS | }||| | }|  |r|d }td|  |W W |rz|  W n   Y n0 |rz|  W S    Y S 0 S W W |rz|  W n   Y n0 |r:z|  W n   Y n0 dS  ty }	 zt	dt
|	  |rz|  W n   Y n0 W Y d}	~	W |rz|  W n   Y n0 |rz|  W n   Y n0 dS d}	~	0 0 W |rz|  W n   Y n0 |rbz|  W n   Y n0 nB|r@z|  W n   Y n0 |r`z|  W n   Y n0 0 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)
       SYSTEMNr   u-   ✅ CRM Contact insertado: OpportunityNumber=u$   ❌ Error al insertar contacto CRM: )r
   closecursorexecutefetchonecommitloggerinfo	Exceptionerrorstrrollback)
contactNamecontactNumbercontactEmailqueryparamsconnr   rowopportunity_numbere r!   D/var/www/html/src/Consultas_SQL/Ventas/Cotiz/CotizEspSolicitudSQL.pyinsert_CRM_CONTACT   s    	r#   )r   returnc           	      C   s  t d|   d}t d|   t d|  d}z2z(t }|sLtd| | }||| f dd |jD }| }|rtt||}t	
d|  d	 d
|v r|d
 r|d
  |d
< |W  d   W W |rz|  W S    Y S 0 S t	d|  d W d   W W |r:z|  W n   Y n0 dS W d   n1 sT0    Y  W n tjy } z2d|  dt| }t	| t|W Y d}~nd}~0  ty } z2d|  dt| }t	| t|W Y d}~nTd}~0  tyB } z2d|  dt| }t	| t|W Y d}~n
d}~0 0 W |rz|  W n   Y n0 n"|rz|  W n   Y n0 0 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>       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
   ConnectionErrorr   r   descriptionr   dictzipr   r   	isoformatr   warningpyodbcErrorr   r   r   )	r   r   r   r   columnsr   resultr    	error_msgr!   r!   r"   buscar_oportunidad_crmf   sp    (


 r;   c           
      C   s  d}d}zpzt  }|s"td|Z | }||| f dd |jD }| }|r.tt||}|dd	 }|dv rt
d	|  d
| d td| |dv rt
d	|  d
| d td| t
d	|  d|d  d|  |W  d   W W |r,z|  W S    Y S 0 S t
d	|  d W d   W W |rpz|  W n   Y n0 dS W d   n1 s0    Y  W n ty } z|W Y d}~nd}~0  tjy } z2d|  dt| }	t
|	 t|	W Y d}~nTd}~0  tyV } z2d|  dt| }	t
|	 t|	W Y d}~n
d}~0 0 W |rz|  W n   Y n0 n"|rz|  W n   Y n0 0 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*      r+   z3verificar_oportunidad_existente.<locals>.<listcomp>Status )VENDIDOVENDIDAATENDIDOr,   z tiene status z - proceso terminadozOPPORTUNITY_CLOSED:)	PENDIENTEzEN DESARROLLOzEN APROBACIONEN_DESARROLLO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
   r0   r   r   r1   r   r2   r3   getupperr   r5   
ValueErrorr   r   r6   r7   r   r   r   )
r   r   r   r   r8   r   r9   statusr    r:   r!   r!   r"   verificar_oportunidad_existente   sp     (

 rI   )datos_oportunidaduser_idversionr$   c           
      C   s  t |}d}d}zLzDt }|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  d   W W |rDz|	  W S    Y S 0 S 1 sN0    Y  W n t
jy } zVdt| }	t|	 ddddddW  Y d}~W |rz|	  W S    Y S 0 S d}~0  ty: } zVd t| }	t|	 dd!d"dddW  Y d}~W |r0z|	  W S    Y S 0 S d}~0 0 W |rz|	  W n   Y n0 n"|rz|	  W n   Y n0 0 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_ContactEmailrA   -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  )r\   messagecode
alert_typestatus_codez'Error inesperado al crear oportunidad: z(Error interno al procesar la oportunidadINTERNAL_ERROR)obtener_nombre_usuarior
   r0   r   r   rE   r   r   r   r   r6   r7   r   r   r   )
rJ   rK   rL   	user_namer   r   r   r]   r    r:   r!   r!   r"   crear_actualizar_oportunidad$  s    
















		rf   )r]   quotation_type_idrK   r$   c           
      C   s  t |}d}d}zzt }|s(td| | }||| ||||f |  |  d| }td| d d|dW  d   W W |rz|  W S    Y S 0 S 1 s0    Y  W n t	j
y0 } zTd	t| }	t|	 d
ddddW  Y d}~W |r&z|  W S    Y S 0 S d}~0  ty } zTdt| }	t|	 d
ddddW  Y d}~W |rz|  W S    Y S 0 S d}~0 0 W |rz|  W n   Y n0 n"|rz|  W n   Y n0 0 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%   r[   z	FormHead z creado exitosamenteT)r\   form_idz*Error de base de datos al crear FormHead: Fz%Error al crear registro de formularior^   r   r\   r_   r`   ra   z$Error inesperado al crear FormHead: z!Error interno al crear formulariorc   )rd   r
   r0   r   r   r   r   r   r   r6   r7   r   r   r   )
r]   rg   rK   re   r   r   r   rh   r    r:   r!   r!   r"   crear_formulario_head  s    



rj   c                 C   s   d S )Nr!   )Zopportunitur!   r!   r"   getDocsUploadedFromOpportunity  s    rk   )rh   	preguntasr$   c                 C   s  t d|   t dt|  t|D ] \}}t d|d  d|  q(d}d}zzlt }|sltdd	}|8 | }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  d   W W |rz|  W S    Y S 0 S 1 s0    Y  W  n tjyB }
 zbdt|
 }t
| t d|  d d!d"d#d$W  Y d}
~
W |r8z|  W S    Y S 0 S d}
~
0  ty }
 zbd%t|
 }t
| t d&|  d d'd(d#d$W  Y d}
~
W |rz|  W S    Y S 0 S d}
~
0 0 W |rz|  W n   Y n0 n"|rz|  W n   Y n0 0 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: r[   u   ✅ DEBUG - Registro z insertado exitosamentezCreados z detalles para FormID T)r\   Zrecords_createdz-Error de base de datos al crear FormDetails: u   ❌ DEBUG - Error SQL: Fz(Error al guardar detalles del formularior^   r   ri   z'Error inesperado al crear FormDetails: u   ❌ DEBUG - Error general: z!Error interno al guardar detallesrc   )r/   len	enumerater
   r0   r   r   zfillr   r   r   r   r   r6   r7   r   r   )rh   rl   irp   r   r   Zregistros_creadosr   indexZ	form_liner    r:   r!   r!   r"   crear_formulario_details  s    



rw   )seller_user_idrh   r]   re   r$   c           
      C   s  d}d}zzt  }|s td| | }||| |d||f |d | d }|  td| d|  d	|d
W  d   W W |rz|  W S    Y S 0 S 1 s0    Y  W n t	j
y4 } zTdt| }	t|	 dddddW  Y d}~W |r*z|  W S    Y S 0 S d}~0  ty } zTdt| }	t|	 dddddW  Y d}~W |rz|  W S    Y S 0 S d}~0 0 W |rz|  W n   Y n0 n"|rz|  W n   Y n0 0 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)r\   task_idz'Error de base de datos al crear tarea: Fu#   Error al crear tarea de cotizaciónr^   r   ri   z!Error inesperado al crear tarea: zError interno al crear tarearc   )r
   r0   r   r   r   r   r   r   r   r6   r7   r   r   r   )
rx   rh   r]   re   r   r   r   ry   r    r:   r!   r!   r"   crear_tarea_cotizacionF  s    	



rz   )rK   r$   c                 C   s  d}d}zzt  }|sFd|  W W |rDz|  W S    Y S 0 S | | }||| f | }|rd|d  }| r|nd|  W  d   W W |rz|  W S    Y S 0 S d|  W  d   W W |r z|  W S    Y S 0 S W d   n1 s0    Y  W nl ty } zRt	
d|  dt|  d|  W  Y d}~W |rz|  W S    Y S 0 S d}~0 0 W |rz|  W n   Y n0 n"|rz|  W n   Y n0 0 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'
            )
    NUsuario_ r   z#Error al obtener nombre de usuario r.   )r
   r   r   r   r   joinsplitstripr   r   r5   r   )rK   r   r   r   r   	full_namer    r!   r!   r"   rd     sf    &	&rd   )rg   r$   c                 C   sJ  d}d}zz(t  }|sPtd|   W W |rLz|  W n   Y n0 dS | | }||| f | }|rt|d }td|  d|  |W  d   W W |rz|  W S    Y S 0 S td|  d W d   W W |rz|  W n   Y n0 dS W d   n1 s*0    Y  W n t	j
y } zJtd	|  d
t|  W Y d}~W |rz|  W n   Y n0 dS d}~0  ty } zJtd|  d
t|  W Y d}~W |rz|  W n   Y n0 dS d}~0 0 W |rFz|  W n   Y n0 n"|rDz|  W n   Y n0 0 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   r5   r   r   r   r   boolr   r6   r7   r   r   r   )rg   r   r   r   r   create_taskr    r!   r!   r"   debe_crear_tarea  s~    (r   c                 C   s  d}d}znzt  }|s>W W |r:z|  W n   Y n0 dS | | }||| f | }|r|d W  d   W W |rz|  W S    Y S 0 S W d   W W |rz|  W n   Y n0 dS W d   n1 s0    Y  W nd tyT } zJtd|  dt|  W Y d}~W |rHz|  W n   Y n0 dS d}~0 0 W |rz|  W n   Y n0 n"|rz|  W n   Y n0 0 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   r5   r   )taskIDr   r   r   r   r    r!   r!   r"   get_FormID_by_TaskID  sd    	&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)rE   )r   Zmapeo_tiposr!   r!   r"   obtener_quotation_type_id2  s    r   c                 C   s  d}d}z~zt  }|s>| W W |r<z|  W S    Y S 0 S | | }||| f | }|r|d rt|d W  d   W W |rz|  W S    Y S 0 S | W  d   W W |rz|  W S    Y S 0 S W d   n1 s0    Y  W nf tyd } zLtd|  dt	|  | W  Y d}~W |rZz|  W S    Y S 0 S d}~0 0 W |rz|  W n   Y n0 n"|rz|  W n   Y n0 0 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   r5   r   )rK   r   r   r   r   r    r!   r!   r"   obtener_seller_user_idM  sd    	$r   )rh   docs_idr$   c                 C   s6  d}d}zzt  }|s"td| | }|||| f |j}|  |dkrtd|  d|  ddiW  d   W W |rz|  W S    Y S 0 S t	d	|  d
 dddW  d   W W |rz|  W S    Y S 0 S W d   n1 s0    Y  W n t
jy } zRdt| }t| ddddW  Y d}~W |rvz|  W S    Y S 0 S d}~0  ty } zRdt| }t| ddddW  Y d}~W |rz|  W S    Y S 0 S d}~0 0 W |r2z|  W n   Y n0 n"|r0z|  W n   Y n0 0 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 r\   Tu   No se encontró formulario z para actualizarFz(Formulario no encontrado para actualizar)r\   r_   z1Error de base de datos al actualizar formulario: z-Error al actualizar formulario con documentosr^   )r\   r_   r`   z+Error inesperado al actualizar formulario: z&Error interno al actualizar formulariorc   )r
   r0   r   r   rowcountr   r   r   r   r5   r6   r7   r   r   r   )rh   r   r   r   r   Zrows_affectedr    r:   r!   r!   r"   actualizar_formulario_con_docs|  s    &


r   )"r6   loggingr   typingr   r   r   r   	getLoggerr   configr   r	   Consultas_SQL.conexionr
   r#   floatr;   r   rI   r   rf   rj   rk   rw   rz   rd   r   r   r   r   r   r2   r   r!   r!   r!   r"   <module>   s(   
SjTmNcP87-/