U
    2iī                     @   s  d 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
mZmZmZ edZddlmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddl	mZ dd Zdd Zd5edddZeeeef  dddZeeeeee f f  dddZ!dd Z"dd Z#dd Z$d d! Z%d"d# Z&d6ed%d&d'Z'e(ed(d)d*Z)eee  dd+d,Z*e ee d-d.d/Z+e ee d0d1d2Z,eee d0d3d4Z-dS )7u   
Archivo: CotizCreatedIngSQL.py
Ruta: src\Consultas_SQL\Operaciones\Ingenieria\Cotiz\CotizCreatedIngSQL.py
Descripción: Módulo para crear cotizaciones del area de ingenierìa
Autor: Equipo de Desarrollo IGSA
Fecha: 2025
    )datetimeN)DictListOptionalUnion)	Blueprintrequestjsonifysessioncotizaciones_especiales_sql)
ProductivoENVIRONMENT)get_connection) upload_document_to_existing_docs)crear_docs_head)enviar_correo_universal)r	   c           
   
   C   s  d}d}zt  }| }||| f | }|sRtd|   W 5 Q R  W dS dd |jD }tt||}||| f | }|r|d nd|d< t|	d	t
r|d	 d
|d	< |W  5 Q R  W S Q R X W n> tk
r }	 ztd|  d|	  W Y dS d}	~	X Y nX dS )u   
    🔹 Obtiene y une la información necesaria para el envío de correo
       basada en el TaskID (tabla Q_SpQ_QuotationTasks).
    🔹 Devuelve un diccionario listo para usar como `template_data`.
    aH  
        SELECT 
            Q_OpportunityCRM.CRM_OpportunityNumber,
            Q_CostingHead.CostingNum,
            Q_QuotationType.FrontEN,
            Q_QuotationType.FrontES,
            Q_CostingHead.CostingDate
        FROM 
            Q_SpQ_QuotationTasks
        INNER JOIN 
            Q_SpQ_FormsHead
            ON Q_SpQ_QuotationTasks.FormID = Q_SpQ_FormsHead.FormID
        INNER JOIN 
            Q_QuotationType
            ON Q_SpQ_FormsHead.QuotationTypeID = Q_QuotationType.QuotationTypeID
        INNER JOIN 
            Q_CostingHead
            ON Q_CostingHead.CostingID = Q_SpQ_QuotationTasks.CostingID
        INNER JOIN
            Q_OpportunityCRM
        ON
            Q_SpQ_QuotationTasks.CRM_OpportunityID = Q_OpportunityCRM.CRM_OpportunityID
        WHERE 
            Q_SpQ_QuotationTasks.TaskID = ?;
    a`  
        SELECT 
            Users.Email
        FROM Users
        INNER JOIN 
            Q_CostingHead
            ON Q_CostingHead.SellerUserID = Users.UserID
        INNER JOIN 
            Q_SpQ_QuotationTasks
            ON Q_SpQ_QuotationTasks.CostingID = Q_CostingHead.CostingID
        WHERE 
            Q_SpQ_QuotationTasks.TaskID = ?;
    u0   ⚠️ No se encontró información para TaskID Nc                 S   s   g | ]}|d  qS r    .0colr   r   |C:\Users\victor.barrera\Documents\proyectos\elepV3\Elep\src\Consultas_SQL\Operaciones\Ingenieria\Cotiz\CotizCreatedIngSQL.py
<listcomp>W   s     z"data_for_email.<locals>.<listcomp>r   EmailZCostingDatez%d/%m/%Y %H:%Mu   ❌ Error en data_for_email(): )r   cursorexecutefetchoneprintdescriptiondictzip
isinstancegetr   strftime	Exception)
task_idZquery1Zquery2connr   Zrow1Zcolumns1Zresult1Zrow2er   r   r   data_for_email   s*    r)   c              
   C   s   | r|rd}d }zzbt }|N | }||| |f |  |d  d|  7  < |W  5 Q R  W W ^S Q R X W nN tk
r } z0d|d< d| dt| |d< | W Y W S d }~X Y nX W 5 |r|   X d S )Nzi
            UPDATE Q_CostingHead
            SET DocsID = ?
            WHERE CostingID = ?
            messagez" | Costing actualizado con DocsID FsuccesszError al actualizar CostingID : )closer   r   r   commitr%   str)DocsID	CostingID	resultadoqueryr'   r   r(   r   r   r   uploadFileAuxiliarl   s"     "r4    )destinatarioTestc              
   C   s   t | }td|  |s:td|   dd|  dS zhd}|dkrN|}n|d }tdd	d
|gi|d}|drtd|d   ntd|d  |W S  tk
r } z*td|  d|  dt|d W Y S d}~X Y nX dS )uq   
    🔹 Usa los datos de data_for_email(task_id)
    🔹 Envía el correo con el template correspondiente
    zDatos para correo: u1   ❌ No se pudieron obtener los datos para TaskID Fz$No se encontraron datos para TaskID )r+   mensajer5   r   z0Emails/Ingenieria/Cotiz/CotizCreatedIngMail.htmlu/   ✅ Costeo creado correctamente - IGSA ElephantTO)template_pathasuntodestinatarios_adicionalestemplate_datar+   u"   ✅ Correo enviado exitosamente a u   ⚠️ Error al enviar correo: r7   u'   ❌ Error al enviar correo para TaskID r,   N)r)   loggerinfor   r   r#   r%   r/   )r&   r6   datadestinatarior2   r(   r   r   r   enviarCorreoCostingCreado   s2     	
rA   )returnc               
   C   s   d} g }zft  T}| @}||  | }|D ]"}||d |d |d d q2W 5 Q R X W 5 Q R X |W S  tk
r } ztd|  g  W Y S d}~X Y nX dS )uo   
    Consulta la tabla Q_Currency para obtener el código, el nombre y el símbolo de las monedas activas.
    zJSELECT CurrencyCode, FrontES, CurrSymbol FROM Q_Currency WHERE Active = 1;r         )CurrencyCodeFrontESZ
CurrSymbolzError al obtener las monedas: N)r   r   r   fetchallappendr%   r   )r3   
currenciesr'   r   rowsrowr(   r   r   r   get_currencies   s    

rL   c              
   C   s   d}g }ztt  b}| N}||| f | }|D ],}||d |d t|d |d d q6W 5 Q R X W 5 Q R X |W S  tk
r } ztd|  g  W Y S d}~X Y nX dS )	ui   
        Consulta la tabla Q_TaxRate para obtener el código y la descripción de los impuestos.
        zgSELECT TaxCode, FrontES, TaxAmount, CurrencyCode FROM Q_TaxRate WHERE Active >= 1 AND CurrencyCode = ?;r   rC   rD      )TaxCoderF   Z	TaxAmountrE   z Error al obtener los impuestos: N)r   r   r   rG   rH   floatr%   r   )rE   r3   taxesr'   r   rJ   rK   r(   r   r   r   	get_taxes   s"    
rQ   c           	      C   s$  d}d }zzt }| | }||| f dd |jD }| }|rtt||}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 nF tjk
r } z&d|  d	| }t| t|W 5 d }~X Y nX W 5 |rz|   W n   Y nX X d S )
Nzs
        SELECT TOP 1 CRM_OpportunityID, QuotationTypeID
        FROM Q_SpQ_FormsHead
        WHERE FormID = ?
    c                 S   s   g | ]}|d  qS r   r   r   r   r   r   r      s     z,obtener_datos_formulario.<locals>.<listcomp>zFormulario z encontrado correctamente.u   No se encontró FormID .z&Error SQL en obtener_datos_formulario(r   r-   r   r   r   r   r   r    r!   r=   r>   warningpyodbcErrorerrorr%   )	form_idr3   r'   r   columnsrK   resultr(   msgr   r   r   obtener_datos_formulario   s0    "
r\   c           	      C   s$  d}d }zzt }| | }||| f dd |jD }| }|rtt||}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 nF tjk
r } z&d|  d	| }t| t|W 5 d }~X Y nX W 5 |rz|   W n   Y nX X d S )
Na%  
        SELECT TOP 1
            UserRoles.RoleID,
            Roles.CompanyID,
            Roles.DivisionID,
            Roles.DepartamentID,
            Profiles.CompanyID AS ProfileCompanyID,
            Profiles.DivisionID AS ProfileDivisionID,
            Profiles.DepartamentID AS ProfileDepartamentID
        FROM Users
        INNER JOIN Profiles ON Users.UserID = Profiles.UserID
        INNER JOIN UserRoles ON Users.UserID = UserRoles.UserID
        INNER JOIN Roles ON UserRoles.RoleID = Roles.RoleID
        WHERE Users.UserID = ?
    c                 S   s   g | ]}|d  qS r   r   r   r   r   r   r     s     z,obtener_contexto_usuario.<locals>.<listcomp>zContexto de usuario z recuperado correctamente.%   No se encontró contexto para UserID rR   z&Error SQL en obtener_contexto_usuario(r   rS   )	user_idr3   r'   r   rY   rK   rZ   r(   r[   r   r   r   obtener_contexto_usuario   s0    "
r_   c               
   C   s   z~z8t }| } d}| | |  }|r2|jndW W FS  tk
rz } z"tdt	|  W Y W dS d}~X Y nX W 5 |    |   X dS )u8   Genera el siguiente número de costing (IDENTITY 1000,1)zf
        SELECT ISNULL(MAX(CostingNum), 999) + 1 AS NextCostingNum
        FROM Q_CostingHead
        i  zError al generar CostingNum: N)
r-   r   r   r   r   ZNextCostingNumr%   r=   rW   r/   )r   r'   r3   rK   r(   r   r   r   generar_costing_num/  s    
 r`   c              '   C   sN  d}d}zz| d}| d}| d}td| d  |rL|sdtdd	id
fW W S td| d|  t|}|stdd| idfW W \S t|}|stdd| idfW W 2S t }| }| dd}|	d |
 d }	|	d }
|
 d| }td|
 d|	 d d}td |	||
||d||d||d|d|d| d| d | d!| d"| d#| d$| d%| d&| d'| d(| d)| d*| d+| d,| d-|d.| d/| d0| d1| d2| d3| d4| d5d6| d7| d8f" td9|
  td:| d d; | d<g }d}| d}|d=krd}n`|d>krd| d!dd?  d| d#dd?   d| d%dd?   d| d'dd?   }nd}td@|dA |rdB}|D ]f}|	|||dC|dD|dE|dF|dG|dH| |dH| |dF f |d7 }qtdI| dJ n
tdK | dL}dM}|	|| dN}|	||d.f |
 }|d }|dkrdO}|	||d.f tdP|d. dQ tdR| dS}|	||f |
 }|rD|d nd}tdT| dU|  tdV|  dW}|	||||f |  tdX|  td6dY||
||d|d.|| d1dZd[d\fW W &S  tjk
r: } z@|r|  td]|  td^t|d_d`f W Y W S d}~X Y n tjk
r } z@|r\|  tda|  tdbt|d_dcf W Y W rS d}~X Y n` tk
r } z@|r|  tdd|  tdet|d_dcf W Y W S d}~X Y nX W 5 |rz|   W n   Y nX |rHz|   td W n   Y nX X dS )fu   
    Endpoint que crea Q_CostingHead y Q_CostingDetail en una transacción.
    Obtiene el último CostingNum, incrementa +1 y lo usa para insertar.
    Nu   🔒 Conexión cerradaZFormIDUserIDSellerUserIDz
costingId r1   rW   u4   Faltan parámetros: FormID y UserID son obligatorios  u.   📋 Iniciando creación de Costing - FormID: z
, UserID: u)   No se encontró información para FormID   r]   VersionrC   z7SELECT ISNULL(MAX(CostingNum), 999) FROM Q_CostingHead;r   -u!   🧮 Generando nuevo CostingNum: u    (último fue )a1  
        INSERT INTO Q_CostingHead (
            CostingNum, Version, QuotationTypeID, UserID, RoleID, SellerUserID,
            CompanyID, DivisionID, DepartamentID, CaseCost,
            DirectCost, IndirectPercent, IndirectAmount,
            FinancePercent, FinanceAmount, UtilityPercent, UtilityAmount,
            OperationPercent, OperationAmount, SalePriceMin,
            DiscountMaxPercent, DiscountMaxAmount, SalePriceList, OvercostFactor,
            CRM_OpportunityID, ApprovalProcessID, PreviusDocsID, DocsID,
            TechnicalTermsAndConditions, RunTimeNumber, RunTimeType, Active,
            CurrencyCode, TaxCode
        )
        VALUES (
            ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
            ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
            ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
        )
        z)Inserting into Q_CostingHead with values:QuotationTypeIDRoleID	CompanyID
DivisionIDDepartamentIDZCaseCostZ
DirectCostZIndirectPercentZIndirectAmountZFinancePercentZFinanceAmountZUtilityPercentZUtilityAmountZOperationPercentZOperationAmountZSalePriceMinZDiscountMaxPercentZDiscountMaxAmountZSalePriceListZOvercostFactorCRM_OpportunityIDZApprovalProcessIDZPreviusDocsIDr0   ZTechnicalTermsAndConditionsZRunTimeNumberZRunTimeTypeZActiveTrE   rN   u9   ✅ Q_CostingHead insertado correctamente con CostingNum=z----case cost: z----ZQ_CostingDetailA)BCd   zOvercostFactor para detalles: z.6fz
            INSERT INTO Q_CostingDetail (
                CostingID, CostingLine, PartNum, PartDescription,
                Qty, UOMCode, UnitPrice, Amount
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
            ZCostingLinePartNumPartDescriptionZQtyUOMCodeZ	UnitPriceu   ✅ z$ items insertados en Q_CostingDetailu4   ⚠️ No hay items en Q_CostingDetail para insertarTaskIDz
        UPDATE Q_SpQ_QuotationTasks
        SET 
            Status = 'COMPLETADO',
            StatusDate = CAST(SYSDATETIMEOFFSET() AT TIME ZONE 'Central America Standard Time' AS DATETIME)
        WHERE TaskID =?;
        z
        SELECT
            COUNT(TaskID) AS NumeroDeTareasPorAsignarNoCompletadas
        FROM
            Q_SpQ_QuotationTasks
        WHERE
            CRM_OpportunityID = ? AND
            Status <> 'COMPLETADO';
        u  
            UPDATE Q_OpportunityCRM
            SET
                Status = 'ATENDIDO',
                UpdatedAt = CAST(SYSDATETIMEOFFSET() AT TIME ZONE 'Central America Standard Time' AS DATETIME) -- Actualiza la fecha de modificación
                --UpdatedBy = 'NOMBRE_USUARIO_QUE_ACTUALIZA' -- Actualiza quién realizó la modificación
            WHERE
                CRM_OpportunityID = ?;
            u   ✅ Oportunidad CRM z actualizada a 'ATENDIDO'zcosting id generado:zh
            select CostingDate
            from Q_CostingHead
            where CostingID = ?;
        u   ✅ CostingDate obtenido: z para CostingID z*task id para actualizar en costing tasks: z
        UPDATE dbo.q_spq_quotationtasks
        SET 
            CostingID = ?,
            CostingDate = ?
        WHERE 
            TaskID = ?
        u)   ✅ Transacción confirmada - CostingID: zCosting creado exitosamente)r1   Z
CostingNumre   rh   rm   ZItemsInsertadosr0   )r+   r*   r?      u   ❌ Error de integridad: zError de integridad de datosrW   detailsi  u   ❌ Error de base de datos: zError en base de datos  u   ❌ Error inesperado: zError al crear costing)r-   r=   r>   r#   r	   r\   r_   r   r   r   r   r   rT   r.   rU   IntegrityErrorrollbackrW   r/   rV   r%   )r?   r'   r   rX   r^   seller_user_idZsub1Zsub2versionZlast_numZcosting_num
costing_idZinsert_head_queryZdetail_itemsZitems_insertadosZcasoZfactorOverCostZinsert_detail_queryitemru   Zquery3Zquery4ZresultQuery4Znumero_de_tareasZquery5Zquery6ZresultQuery6Zcosting_dateZquery7db_errorr(   r   r   r   generar_costing_headSQLF  s<   




&





	


 . . 4  r   c                 C   sB  t d d}d}zԐzt d|   | d}| d}t d|  t d|  |rf|s~td	d
idfW W nS t d|  t }| }d}||||f |jdkrt 	d| d td	d| idfW W S |
  t d| d|  tdd| ddfW W S  tjk
r } z@|rH|  t d|  tdt|ddf W Y W rS d}~X Y n` tk
r } z@|r|  t d|  tdt|ddf W Y W S d}~X Y nX W 5 |r
z|  W n   Y nX |r4z|  t d W n   Y nX X d}d}zzt } | d}| d}|rl|std	d
idfW W pS t d|  t }| }d}||||f |jdkrt 	d| d td	d| idfW W S |
  t d| d|  tdd| ddfW W S  tjk
r } z@|rP|  t d|  tdt|ddf W Y W rS d}~X Y n` tk
r } z@|r|  t d|  tdt|ddf W Y W S d}~X Y nX W 5 |rz|  W n   Y nX |r<z|  t d W n   Y nX X dS )z>
    Endpoint para actualizar el DocsID en Q_CostingHead.
    u8   🔄 Iniciando actualización de DocsID en Q_CostingHeadNu*   🔒 Conexión a la base de datos cerrada.u%   Datos recibidos para actualización: r1   r0   zcostingId recibido: zdocsId recibido: rW   u7   Faltan parámetros: CostingID y DocsID son obligatoriosrc   u8   📋 Iniciando actualización de DocsID para CostingID: zY
        UPDATE Q_CostingHead
        SET DocsID = ?
        WHERE CostingID = ?
        r   u$   ⚠️ No se encontró el CostingID z para actualizar.u*   No se encontró un registro con CostingID rd   u(   ✅ DocsID actualizado correctamente a 'z' para CostingID Tz.DocsID actualizado correctamente en CostingID )r+   r*      u1   ❌ Error de base de datos al actualizar DocsID: zError en la base de datosrw   ry   u+   ❌ Error inesperado al actualizar DocsID: u   Ocurrió un error inesperado)r=   r>   r-   r#   r	   r   r   r   rowcountrT   r.   rU   rV   r{   rW   r/   r%   r   get_json)r?   r'   r   r~   docs_idupdate_queryr   r(   r   r   r   update_costing_head_docsidSQLd  s    




 . 4  


 . 4  r   General)r1   c           
      C   sz   t |dt|}|d }g }| D ]>}t|||jd| d| d}	|	d r ||	d d  q t|d	k|t||d
S )uA   
    Patrón simplificado para casos con una sola categoría
    ZQ_CostingHeadr   zArchivo de zVentas/Costeo/)file_objr   titler   ruta_completar+   r?   download_urlr   )r+   r   archivos_subidosurls)r   obtener_nombre_usuarior   filenamerH   len)
archivos	modulo_idr^   r1   	categoriaZdocs_resultr   Zurls_generadasarchivor2   r   r   r   upload_archivos_simple  s$    
r   )r^   rB   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'
            )
    NUsuario_ r   z#Error al obtener nombre de usuario r,   )r-   r   r   r   r   joinsplitstripr%   r=   rT   r/   )r^   r3   r'   r   rK   	full_namer(   r   r   r   r   1  s,    (*(r   c                  C   s  d} d}zzt }|s td| | }||  dd |jD }|	 }|rg }|D ]F}t
t||}dD ]$}||krr|| rr||  ||< qr|| q\tdt| d	 |W  5 Q R  W W S td
 W 5 Q R  W W dS W 5 Q R X W n tjk
r@ }	 z$dt|	 }
t|
 t|
W 5 d}	~	X Y n tk
r }	 z$dt|	 }
t|
 t|
W 5 d}	~	X Y nD tk
r }	 z$dt|	 }
t|
 t|
W 5 d}	~	X Y nX W 5 |rz|   W n  tk
r   td Y nX X dS )un  
    Busca todos los datos de score en la tabla Score de la base de datos

    Returns:
        List[Dict]: Lista de diccionarios con los datos de los scores encontrados
        None: Si no se encuentra ningún registro

    Raises:
        ConnectionError: Si no se puede establecer conexión con la BD
        Exception: Para otros errores durante la consulta
    z)
       SELECT * FROM Score;
       
    Nu$   Error al cerrar la conexión a la BD4   No se pudo establecer conexión con la base de datosc                 S   s   g | ]}|d  qS r   r   r   columnr   r   r   r     s     z buscar_score.<locals>.<listcomp>)	CreatedAt	UpdatedAtzSe encontraron z registros de scorez-No se encontraron registros en la tabla Scorez-Error de base de datos al buscar los scores: u)   Error de conexión al buscar los scores: z'Error inesperado al buscar los scores: )r-   r%   r=   rT   r   ConnectionErrorr   r   r   rG   r    r!   	isoformatrH   r>   r   rU   rV   r/   rW   )r3   r'   r   rY   rJ   resultsrK   rZ   
date_fieldr(   	error_msgr   r   r   buscar_scorek  sP    

"


r   )r&   rB   c           	      C   s  d}d}zzt }|s t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
r. } z*d
|  dt| }t	| t|W 5 d}~X Y n tk
rv } 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 |rz|   W n   Y nX X dS )za
    Busca datos de la oportunidad en la tabla Q_CRM

    Args:

    Returns:

    Raises:


    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_SpQ_QuotationTasks  
            JOIN Q_SpQ_FormsHead   
            ON  Q_SpQ_QuotationTasks.FormID = Q_SpQ_FormsHead.FormID
            JOIN Q_OpportunityCRM  
            ON Q_SpQ_FormsHead.CRM_OpportunityID = Q_OpportunityCRM.CRM_OpportunityID
            JOIN Q_CRM  
            ON Q_OpportunityCRM.CRM_OpportunityNumber = Q_CRM.CRM_OpportunityNumber
        WHERE
            Q_SpQ_QuotationTasks.taskID = ?
            AND Q_CRM.Active = 1
        ORDER BY Q_CRM.CRM_Version DESC;
    Nr   c                 S   s   g | ]}|d  qS r   r   r   r   r   r   r     s     z$buscar_tarea_crm.<locals>.<listcomp>Oportunidad  encontrada exitosamenter   " no encontrada en la base de datosz0Error de base de datos al buscar la oportunidad r,   u+   Error de conexión al buscar la oprtunidad z*Error inesperado al buscar la oportunidad r-   r   r   r   r   r   r   r    r!   r=   r>   r   rT   rU   rV   r/   rW   r%   )	r&   r3   r'   r   rY   rK   rZ   r(   r   r   r   r   buscar_tarea_crm  sH    #"


r   )opportunity_numberrB   c           	      C   s  d}d}zzt }|s t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
r. } z*d
|  dt| }t	| t|W 5 d}~X Y n tk
rv } 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 |rz|   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
    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
    Nr   c                 S   s   g | ]}|d  qS r   r   r   r   r   r   r   _  s     z*buscar_oportunidad_crm.<locals>.<listcomp>r   r   r   r   z-Error de base de datos al buscar oportunidad r,   u)   Error de conexión al buscar oportunidad z'Error inesperado al buscar oportunidad r   )	r   r3   r'   r   rY   rK   rZ   r(   r   r   r   r   buscar_oportunidad_crm)  sH    "


r   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>Statusr5   )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 re   z
 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    r!   r#   upperr=   rT   
ValueErrorr>   rU   rV   r/   rW   r%   )
r   r3   r'   r   rY   rK   rZ   statusr(   r   r   r   r   verificar_oportunidad_existente  sN     "

r   )r5   )r   ).__doc__r   rU   loggingtypingr   r   r   r   flaskr   r   r	   r
   	getLoggerr=   configr   r   Consultas_SQL.conexionr   #App.Utilities_module.DocsManagementr   )Consultas_SQL.Utilities.DocsManagementSQLr   #App.Utilities_module.MailManagementr   r)   r4   r/   rA   rL   rO   rQ   r\   r_   r`   r   r   r   intr   r   r   r   r   r   r   r   r   <module>   s>   
O'"(0    /:Png