a
    $9i                     @   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dd Zd7e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'd8ed'd(d)Z(e)ed*d+d,Z*eee  dd-d.Z+e!ee d/d0d1Z,e!ee d2d3d4Z-eee d2d5d6Z.dS )9u   
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sessionZ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 | }|sTtd|   W d   W dS dd |jD }tt||}||| f | }|r|d nd|d< t|	d	t
r|d	 d
|d	< |W  d   W S 1 s0    Y  W n< ty  }	 z"td|  d|	  W Y d}	~	dS d}	~	0 0 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   R/var/www/html/src/Consultas_SQL/Operaciones/Ingenieria/Cotiz/CotizCreatedIngSQL.py
<listcomp>W       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result1row2er   r   r   data_for_email   s*    (r*   c              
   C   s  d}d}zzRt  }| }d}||| |f | }|W W |durL|  |dur\|  S  ty } z@td|  g W  Y d}~W |dur|  |dur|  S d}~0 0 W |dur|  |dur|  n$|dur|  |du r|  0 dS )zv
    Consulta los documentos asociados a una oportunidad y form (task)
    y regresa las filas crudas del cursor.
    Na  
            SELECT
                Q_SpQ_FormsHead.CRM_OpportunityID,
                Q_SpQ_FormsHead.FormID,
                Q_SpQ_DocsDetail.Title,
                Q_SpQ_DocsDetail.Ruta,
                Q_SpQ_DocsDetail.Type
            FROM
                Q_SpQ_FormsHead
            LEFT JOIN Q_SpQ_DocsHead
                ON Q_SpQ_FormsHead.DocsID = Q_SpQ_DocsHead.DocsID
            LEFT JOIN Q_SpQ_DocsDetail
                ON Q_SpQ_DocsHead.DocsID = Q_SpQ_DocsDetail.DocsID
            WHERE 
                Q_SpQ_FormsHead.CRM_OpportunityID = ?
                AND Q_SpQ_FormsHead.FormID = ?
                AND Q_SpQ_FormsHead.DocsID IS NOT NULL
        zError al consultar documentos: )r   r   r   fetchallcloser%   r   )oportunity_idr&   
connectionr   queryrowsr)   r   r   r   &consultar_docs_por_oportunidad_y_tareal   s<    

r1   c              
   C   s,  d|vrd|d< | d u r"| d} | r(|r(d}d }zzxt }|Z | }||| |f |  |d  d|  7  < |W  d    W W |r|  S 1 s0    Y  W nT ty } z:d|d< dt| |d< |W  Y d }~W | r|  S d }~0 0 W |r(|  n|r&|  0 |S )	Nmessage docs_idY
        UPDATE Q_CostingHead
        SET DocsID = ?
        WHERE CostingID = ?
        z" | Costing actualizado con DocsID Fsuccessz
Error DB: )r#   r   r   r   commitr,   r%   str)DocsID	CostingID	resultador/   r'   r   r)   r   r   r   uploadFileAuxiliar   s<    


r<   r3   )destinatarioTestc              
   C   s   t | }td|  |s:td|   dd|  dS znd}|dkrN|}n|d }tdd	|gg d
d|d}|drtd|d   ntd|d  |W S  ty } z.td|  d|  dt|dW  Y d}~S d}~0 0 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 )r6   mensajer3   r   z0Emails/Ingenieria/Cotiz/CotizCreatedIngMail.htmlu/   ✅ Costeo creado correctamente - IGSA Elephant)zvictor.barrera.@igsa.com.mxzvictor.cervantes@igsa.com.mxzalexis.moreno@igsa.com.mx)TOCC)template_pathasuntodestinatarios_adicionalestemplate_datar6   u"   ✅ Correo enviado exitosamente a u   ⚠️ Error al enviar correo: r>   u'   ❌ Error al enviar correo para TaskID : N)r*   loggerinfor   r   r#   r%   r8   )r&   r=   datadestinatarior;   r)   r   r   r   enviarCorreoCostingCreado   s2    

rJ   )returnc               
   C   s   d} g }zt  r}| J}||  | }|D ]"}||d |d |d d q2W d   n1 sj0    Y  W d   n1 s0    Y  |W S  ty } ztd|  g W  Y d}~S d}~0 0 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
CurrSymbolNzError al obtener las monedas: )r   r   r   r+   appendr%   r   )r/   
currenciesr'   r   r0   rowr)   r   r   r   get_currencies   s    

BrS   c              
   C   s   d}g }zt  }| X}||| f | }|D ],}||d |d t|d |d d q6W d   n1 sx0    Y  W d   n1 s0    Y  |W S  ty } ztd|  g W  Y d}~S d}~0 0 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   rL   rM      )TaxCoderO   Z	TaxAmountrN   Nz Error al obtener los impuestos: )r   r   r   r+   rP   floatr%   r   )rN   r/   Ztaxesr'   r   r0   rR   r)   r   r   r   	get_taxes   s"    
FrW   c           	      C   s  d}d }zhzt  }| | }||| f dd |jD }| }|rtt||}td|  d |W  d    W W |rz|	  W S    Y S 0 S t
d|  d W d    W W |rz|	  W n   Y n0 d S W d    n1 s0    Y  W nJ tjyN } z.d|  d	| }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 )
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     r   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!   rF   rG   r,   warningpyodbcErrorerrorr%   )	form_idr/   r'   r   columnsrR   resultr)   msgr   r   r   obtener_datos_formulario  sR    &
 rb   c           	      C   s  d}d }zhzt  }| | }||| f dd |jD }| }|rtt||}td|  d |W  d    W W |rz|	  W S    Y S 0 S t
d|  d W d    W W |rz|	  W n   Y n0 d S W d    n1 s0    Y  W nJ tjyN } z.d|  d	| }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 )
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   P  r   z,obtener_contexto_usuario.<locals>.<listcomp>zContexto de usuario z recuperado correctamente.%   No se encontró contexto para UserID rX   z&Error SQL en obtener_contexto_usuario(r   rY   )	user_idr/   r'   r   r_   rR   r`   r)   ra   r   r   r   obtener_contexto_usuario9  sR    &
 re   c               
   C   s   zzFt  } |  }d}|| | }|r2|jndW W |  |   S  ty } z4tdt	|  W Y d}~W |  |   dS d}~0 0 W |  |   n|  |   0 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   ZNextCostingNumr,   r%   rF   r]   r8   )r'   r   r/   rR   r)   r   r   r   generar_costing_numi  s(    

rf   c              '   C   s|  d}d}z z|  d}|  d}|  d}td|  d  |rL|stddid	fW W |r|z|  W n   Y n0 |rz|  td
 W S    Y S 0 S td| d|  t|}|s.tdd| idfW W |rz|  W n   Y n0 |r,z|  td
 W S    Y S 0 S t|}|stdd| idfW W |rtz|  W n   Y n0 |rz|  td
 W S    Y S 0 S 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rbd}nZ|d>v rd|  d!dd?  d|  d#dd?   d|  d%dd?   d|  d'dd?   }td@|dA |rXdB}|D ]f}|	||| dC| dD| dE| dF| dG| dH| | dH| | dF f |d7 }qtdI| dJ n
tdK |  dL}dM}|	|| dN}|	|| d.f |
 }|d }|dkrdO}|	|| d.f tdP| d. dQ tdR| dS}|	||f |
 }|r|d nd}tdT| dU|  tdV|  dW}|	||||f |  tdX|  td6dY||
|| d| d.||  d1dZd[d\fW W |rz|  W n   Y n0 |rz|  td
 W S    Y S 0 S  tjy } z|r|  td]|  td^t|d_d`fW  Y d}~W |r^z|  W n   Y n0 |rz|  td
 W S    Y S 0 S d}~0  tjy8 } z|r|  tda|  tdbt|d_dcfW  Y d}~W |rz|  W n   Y n0 |r.z|  td
 W S    Y S 0 S d}~0  ty } z|rV|  tdd|  tdet|d_dcfW  Y d}~W |rz|  W n   Y n0 |rz|  td
 W S    Y S 0 S d}~0 0 W |r z|  W n   Y n0 |rxz|  td
 W n   Y n0 nL|rLz|  W n   Y n0 |rvz|  td
 W n   Y n0 0 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.
    NZFormIDUserIDSellerUserIDz
costingId r:   r]   u4   Faltan parámetros: FormID y UserID son obligatorios  u   🔒 Conexión cerradau.   📋 Iniciando creación de Costing - FormID: z
, UserID: u)   No se encontró información para FormID   rc   VersionrL   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PreviusDocsIDr9   ZTechnicalTermsAndConditionsZRunTimeNumberZRunTimeTypeZActiveTrN   rU   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)r:   Z
CostingNumrk   rn   rs   ZItemsInsertadosr9   )r6   r2   rH      u   ❌ Error de integridad: zError de integridad de datosr]   detailsi  u   ❌ Error de base de datos: zError en base de datos  u   ❌ Error inesperado: zError al crear costing)r#   rF   rG   r	   r,   rb   re   r   r   r   r   r   rZ   r7   r[   IntegrityErrorrollbackr]   r8   r\   r%   )rH   r'   r   r^   rd   seller_user_idZsub1Zsub2versionZlast_numZcosting_num
costing_idZinsert_head_queryZdetail_itemsZitems_insertadosZcasoZfactorOverCostZinsert_detail_queryitemr{   Zquery3Zquery4ZresultQuery4Znumero_de_tareasZquery5Zquery6ZresultQuery6Zcosting_dateZquery7db_errorr)   r   r   r   generar_costing_headSQL  s   


 }   t  p 

&





	


!"
"
"r   c                 C   s  t d d}d}z|zt d|   | d}| d}t d|  t d|  |rf|stdd	id
fW W |rz|  W n   Y n0 |rz|  t d W S    Y S 0 S t d|  t }| }d}||||f |jdkrtt 	d| d tdd| idfW W |rHz|  W n   Y n0 |rrz|  t d W S    Y S 0 S |
  t d| d|  tdd| ddfW W |rz|  W n   Y n0 |rz|  t d W S    Y S 0 S  tjy } z|r|  t d|  tdt|ddfW  Y d}~W |rjz|  W n   Y n0 |rz|  t d W S    Y S 0 S d}~0  tyB } z|r|  t d|  tdt|ddfW  Y d}~W |rz|  W n   Y n0 |r8z|  t d W S    Y S 0 S d}~0 0 W |rfz|  W n   Y n0 |rz|  t d W n   Y n0 nL|rz|  W n   Y n0 |rz|  t d W n   Y n0 0 d}d}z\zt } | d}| d}|r|sttdd	id
fW W |rHz|  W n   Y n0 |rrz|  t d W S    Y S 0 S t d|  t }| }d}||||f |jdkr(t 	d| d tdd| idfW W |rz|  W n   Y n0 |r&z|  t d W S    Y S 0 S |
  t d| d|  tdd| ddfW W |rz|  W n   Y n0 |rz|  t d W S    Y S 0 S  tjyR } z|r|  t d|  tdt|ddfW  Y d}~W |rz|  W n   Y n0 |rHz|  t d W S    Y S 0 S d}~0  ty } z|rp|  t d|  tdt|ddfW  Y d}~W |rz|  W n   Y n0 |rz|  t d W S    Y S 0 S d}~0 0 W |rz|  W n   Y n0 |rz|  t d W n   Y n0 nL|rfz|  W n   Y n0 |rz|  t d W n   Y n0 0 dS )z>
    Endpoint para actualizar el DocsID en Q_CostingHead.
    u8   🔄 Iniciando actualización de DocsID en Q_CostingHeadNu%   Datos recibidos para actualización: r:   r9   zcostingId recibido: zdocsId recibido: r]   u7   Faltan parámetros: CostingID y DocsID son obligatoriosri   u*   🔒 Conexión a la base de datos cerrada.u8   📋 Iniciando actualización de DocsID para CostingID: r5   r   u$   ⚠️ No se encontró el CostingID z para actualizar.u*   No se encontró un registro con CostingID rj   u(   ✅ DocsID actualizado correctamente a 'z' para CostingID Tz.DocsID actualizado correctamente en CostingID )r6   r2      u1   ❌ Error de base de datos al actualizar DocsID: zError en la base de datosr}   r   u+   ❌ Error inesperado al actualizar DocsID: u   Ocurrió un error inesperado)rF   rG   r#   r	   r,   r   r   r   rowcountrZ   r7   r[   r\   r   r]   r8   r%   r   get_json)rH   r'   r   r   r4   update_queryr   r)   r   r   r   update_costing_head_docsidSQL  s   


;!"
"

;!"
"r   General)r:   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_CostingHeadr4   zArchivo de zVentas/Costeo/)file_objr4   titler   ruta_completar6   rH   download_urlr   )r6   r4   archivos_subidosurls)r   obtener_nombre_usuarior   filenamerP   len)
archivosZ	modulo_idrd   r:   Z	categoriaZdocs_resultr4   Zurls_generadasarchivor;   r   r   r   upload_archivos_simpleI  s$    
r   )rd   rK   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'
            )
    NZUsuario_ r   z#Error al obtener nombre de usuario rE   )r   r,   r   r   r   joinsplitstripr%   rF   rZ   r8   )rd   r/   r'   r   rR   	full_namer)   r   r   r   r   h  sf    &	&r   c                  C   s  d} d}zvzlt  }|s"td|> | }||  dd |jD }| }|rg }|D ]F}tt||}dD ]$}||v rx|| rx||  ||< qx|	| qbt
dt| d |W  d   W W |rz|  W S  ty   t
d	 Y S 0 S t
d
 W d   W W |rTz|  W n tyR   t
d	 Y n0 dS W d   n1 sn0    Y  W n tjy }	 z,dt|	 }
t
|
 t|
W Y d}	~	nd}	~	0  ty }	 z,dt|	 }
t
|
 t|
W Y d}	~	nNd}	~	0  tyJ }	 z,dt|	 }
t
|
 t|
W Y d}	~	n
d}	~	0 0 W |rz|  W n ty~   t
d	 Y n0 n4|rz|  W n ty   t
d	 Y n0 0 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;
       
    N4   No se pudo establecer conexión con la base de datosc                 S   s   g | ]}|d  qS r   r   r   columnr   r   r   r     r   z buscar_score.<locals>.<listcomp>)	CreatedAtZ	UpdatedAtzSe encontraron z registros de scoreu$   Error al cerrar la conexión a la BDz-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   ConnectionErrorr   r   r   r+   r    r!   	isoformatrP   rF   rG   r   r,   r%   rZ   r[   r\   r8   r]   )r/   r'   r   r_   r0   resultsrR   r`   Z
date_fieldr)   	error_msgr   r   r   buscar_score  sr    

(


 r   )r&   rK   c           	      C   sd  d}d}z2z(t  }|s"t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 s*0    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y } z2d|  dt| }t| t|W Y d}~n
d}~0 0 W |r`z|  W n   Y n0 n"|r^z|  W n   Y n0 0 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   /  r   z$buscar_tarea_crm.<locals>.<listcomp>Oportunidad  encontrada exitosamenter   " no encontrada en la base de datosz0Error de base de datos al buscar la oportunidad rE   u+   Error de conexión al buscar la oprtunidad z*Error inesperado al buscar la oportunidad r   r   r   r   r   r   r    r!   rF   rG   r   r,   rZ   r[   r\   r8   r]   r%   )	r&   r/   r'   r   r_   rR   r`   r)   r   r   r   r   buscar_tarea_crm  sj    #(


 r   )opportunity_numberrK   c           	      C   sd  d}d}z2z(t  }|s"t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 s*0    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y } z2d|  dt| }t| t|W Y d}~n
d}~0 0 W |r`z|  W n   Y n0 n"|r^z|  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
    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     r   z*buscar_oportunidad_crm.<locals>.<listcomp>r   r   r   r   z-Error de base de datos al buscar oportunidad rE   u)   Error de conexión al buscar oportunidad z'Error inesperado al buscar oportunidad r   )	r   r/   r'   r   r_   rR   r`   r)   r   r   r   r   buscar_oportunidad_crm`  sj    (


 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>Statusr3   )ZVENDIDOZVENDIDAZATENDIDOr   z tiene status z - proceso terminadozOPPORTUNITY_CLOSED:)Z	PENDIENTEzEN DESARROLLOzEN APROBACIONZEN_DESARROLLOZEN_APROBACIONz - proceso activozOPPORTUNITY_IN_PROCESS:u    encontrada con versión rk   z
 y status z no encontradaz0Error de base de datos al verificar oportunidad rE   z*Error inesperado al verificar oportunidad )r   r   r   r   r   r   r    r!   r#   upperrF   rZ   
ValueErrorrG   r,   r[   r\   r8   r]   r%   )
r   r/   r'   r   r_   rR   r`   statusr)   r   r   r   r   verificar_oportunidad_existente  sp     (

 r   )r3   )r   )/__doc__r   r[   loggingtypingr   r   r   r   flaskr   r   r	   r
   	getLoggerrF   configr   r   Consultas_SQL.conexionr   #App.Utilities_module.DocsManagementr   )Consultas_SQL.Utilities.DocsManagementSQLr   #App.Utilities_module.MailManagementr   r*   r1   r<   r8   rJ   rS   rV   rW   rb   re   rf   r   r   r   intr   r   r   r   r   r   r   r   r   <module>   s@   
O.$("(0   /:Png