
    /Si)                     p   S SK J r   S SKJr  S SKrS SKrS SKJrJrJrJ	r	  S SK
Jr  \R                  " S5      r " S S5      r " S	 S
5      rS rS\\\      4S jrS\S\\   4S jrS\S\\   4S jrS\S\\   S\S\4S jrS\S\S\S\4S jrS\S\S\S\4S jrS\S\S\S\4S jrS\S\S\4S jrg)    datetime)DecimalN)OptionalListDictUnionget_connectionrecepcion_cotizacion_sqlc            9           \ rS rSrSr        S$S\S\S\S\S\S	\S
\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\48S  jjrS!\	4S" jr
S#rg)%OpportunityAndCostingDTO   uI   DTO para la información unificada de Oportunidad y Encabezado de Costeo.N
costing_idcrm_opportunity_numbercrm_contact_namecrm_contact_typecrm_assigned_salespersoncrm_contact_adresscrm_contact_coloniacrm_contact_citycrm_contact_numbercrm_contact_countrycrm_contact_legal_identifiercrm_contact_zipcrm_contact_statecrm_contact_email	case_costsale_price_listsale_price_mindiscount_max_percentrun_time_numberrun_time_typetechnical_terms_and_conditionsFinancePercentTaxCodeCurrencyCodeQ_TaxRate_FrontESQ_TaxRate_FrontENQ_Currency_FrontESQ_Currency_FrontENc                 z   Xl         X l        X0l        X@l        XPl        X`l        Xpl        Xl        Xl        Xl	        Xl
        Xl        Xl        Xl        Xl        UU l        UU l        UU l        UU l        UU l        U4U l        UU l        U4U l        U4U l        U4U l        U4U l        U4U l        UU l        g )N)	CostingIDCRM_OpportunityNumberCRM_ContactNameCRM_ContactTypeCRM_AssignedSalespersonCRM_ContactAdressCRM_ContactColoniaCRM_ContactCityCRM_ContactNumberCRM_ContactCountryCRM_ContactLegalIdentifierCRM_ContactZipCRM_ContactStateCRM_ContactEmailCaseCostSalePriceListSalePriceMinDiscountMaxPercentRunTimeNumberRunTimeTypeTechnicalTermsAndConditionsr%   r&   r'   r(   r)   r*   r+   )selfr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   s                                kC:\Users\victor.barrera\Documents\proyectos\elepV3\Elep\src\Consultas_SQL\Ventas\Cotiz\RecepcionCotizSQL.py__init__!OpportunityAndCostingDTO.__init__   s     $%;"//'?$!3"5/!3"5*F'- 1 1!,*"6,(+I+J(,x(M!2!3!2!3"4"5"4    returnc                 B   0 SU R                   _SU R                  _SU R                  _SU R                  _SU R                  _SU R
                  _SU R                  _SU R                  _S	U R                  _S
U R                  _SU R                  _SU R                  _SU R                  _SU R                  _SU R                  _S[        U R                   5      _S[        U R"                  5      _[        U R$                  5      U R&                  U R(                  U R*                  S   U R,                  b  [        U R,                  5      OSU R.                  S   U R0                  S   U R2                  S   U R4                  S   U R6                  S   U R8                  S.E$ )z2Convierte el objeto a un diccionario serializable.r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r   N)r>   r?   r@   rA   r%   r&   r'   r(   r)   r*   r+   )r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   floatr<   r=   r>   r?   r@   rA   r%   r&   r'   r(   r)   r*   r+   )rB   s    rC   to_dict OpportunityAndCostingDTO.to_dict>   s   

#T%?%?
 t33
 t33	

 &t'C'C
  !7!7
 !$"9"9
 t33
  !7!7
 !$"9"9
 )$*I*I
 d11
  5 5
  5 5
 
  U4#5#56!
" E$"3"34#
$ #((?(?"@!//+++/+K+KA+N<@<O<O<[eD$7$78aeQ --a0!%!7!7!:!%!7!7!:"&"9"9!"<"&"9"99
 	
rF   )r1   r2   r4   r3   r6   r:   r7   r/   r5   r9   r0   r8   r.   r;   r-   r'   r>   r%   r+   r*   r)   r(   r?   r@   r<   r=   r&   rA   )
NNNNNNNNNN)__name__
__module____qualname____firstlineno____doc__strrI   intrD   dictrJ   __static_attributes__ rF   rC   r   r      sA   S gk $ !%!%"&"&*53 *5 *5WZ *5*59<*5RU*5 *547*5MP*5 !*5 AD*5 	*5 25	*5 JM	*5
 *5
 */*5
 AF*5
 ^c*5 *5 58*5 ad*5 *5 *5 *5 *5 *5  *5  *5Z
 
rF   r   c                   
   \ rS rSrSr\S\S\\   4S j5       r	\S\
\\\\\4   4      4S j5       r\S\
\\\4      4S j5       r\S\S\
\   4S j5       r\S	\S\4S
 j5       r\S	\S\4S j5       r\S\S\4S j5       rSrg)RecepcionCotizSQL`   uY   Clase de servicio para manejar la lógica de recepción de datos de costeo y oportunidad.costing_numrG   c                    Sn [        5        nUR                  5        nUR                  X5        UR                  5       nSSS5        W(       a  [	        S<0 SUS   _SUS   _SUS   _S	US
   _SUS   _SUS   _SUS   _SUS   _SUS   _SUS   _SUS   _SUS   _SUS   _SUS   _SUS    _S!US"   _S#US$   _S%US&   _S'US(   _S)US*   _S+US,   _S-US.   _S/US0   _S1US2   _S3US4   _S5US6   _S7US8   _S9US:   _6sSSS5        $  SSS5        g! , (       d  f       N= f! , (       d  f       g= f! [
         a  n[        S;U 35         SnAgSnAff = f)=zc
Consulta unificada que obtiene los datos de Q_CostingHead y Q_OpportunityCRM
en una sola llamada.
aO  
            SELECT TOP 1
                Q_CostingHead.CostingID,
                Q_OpportunityCRM.CRM_OpportunityNumber,
                Q_OpportunityCRM.CRM_ContactName,
                Q_OpportunityCRM.CRM_ContactType,
                Q_OpportunityCRM.CRM_AssignedSalesperson,
                Q_OpportunityCRM.CRM_ContactAdress,
                Q_OpportunityCRM.CRM_ContactColonia,
                Q_OpportunityCRM.CRM_ContactCity,
                Q_OpportunityCRM.CRM_ContactNumber,
                Q_OpportunityCRM.CRM_ContactCountry,
                Q_OpportunityCRM.CRM_ContactLegalIdentifier,
                Q_OpportunityCRM.CRM_ContactZip,
                Q_OpportunityCRM.CRM_ContactState,
                Q_OpportunityCRM.CRM_ContactEmail,
                Q_CostingHead.CaseCost,
                Q_CostingHead.SalePriceList,
                Q_CostingHead.SalePriceMin,
                Q_CostingHead.DiscountMaxPercent,
                Q_CostingHead.RunTimeNumber,
                Q_CostingHead.RunTimeType,
                Q_CostingHead.TechnicalTermsAndConditions,
                Q_CostingHead.FinancePercent,
                Q_CostingHead.TaxCode,
                Q_CostingHead.CurrencyCode,
                Q_TaxRate.FrontES as Q_TaxRate_FrontES,
                Q_TaxRate.FrontEN as Q_TaxRate_FrontEN,
                Q_Currency.FrontES as Q_Currency_FrontES,
                Q_Currency.FrontEN as Q_Currency_FrontEN
            FROM
                Q_CostingHead
            INNER JOIN
                Q_OpportunityCRM ON Q_CostingHead.CRM_OpportunityID = Q_OpportunityCRM.CRM_OpportunityID
            LEFT JOIN
                Q_TaxRate ON Q_TaxRate.TaxCode = Q_CostingHead.TaxCode 
                        AND Q_TaxRate.CurrencyCode = Q_CostingHead.CurrencyCode 
                        AND Q_TaxRate.Active >= 1
            LEFT JOIN
                Q_Currency ON Q_Currency.CurrencyCode = Q_CostingHead.CurrencyCode
                        AND Q_Currency.Active >= 1
            WHERE
                Q_CostingHead.CostingNum = ?
            ORDER BY
                Q_CostingHead.Version DESC;
        Nr   r   r      r      r      r      r      r      r      r      r   	   r   
   r      r      r      r   r   r      r       r!      r"      r#      r$      r%      r&      r'      r(      r)      r*      r+      z#Error al obtener datos unificados: rU   )r   cursorexecutefetchoner   	Exceptionprint)rY   queryconnru   rowes         rC   get_unified_data_by_costing_num1RecepcionCotizSQL.get_unified_data_by_costing_numc   s2   -\	!T[[]fNN56 //+C # 3 #&q6BEa&[^_`[a),QJMa&ehijek -0F FIV adde`f -0F	 RUUWQX	
 ),B
 DGr7
 _bbd^e #&b' <?r7 TWWYSZ ruuwqx ),B @C2w hkkmgn (+2w !$B &)W -0G -0G .1W .1W "!, - "!"] "!.  	7s;<	sX   
D6 D%"DB?D% 	D6 
D%D6 
D"	D%%
D3/D6 3D6 6
E EEc                     Sn / n [        5        nUR                  5        nUR                  U 5        UR                  5       nU H.  nUR	                  US   US   [        US   5      US   S.5        M0     SSS5        SSS5        U$ ! , (       d  f       N= f! , (       d  f       U$ = f! [         a  n[        SU 35        / s SnA$ SnAff = f)	uY   
Consulta la tabla Q_TaxRate para obtener el código y la descripción de los impuestos.
zTSELECT TaxCode, FrontES, TaxAmount, CurrencyCode    FROM Q_TaxRate WHERE Active = 1;r   r[   r\   r]   )r&   FrontES	TaxAmountr'   Nz Error al obtener los impuestos: r   ru   rv   fetchallappendrI   rx   ry   )rz   taxesr{   ru   rowsr|   r}   s          rC   	get_taxesRecepcionCotizSQL.get_taxes   s    
 g	!T[[]fNN5)!??,D#QCFY^FZ$58V&= >  $ # " L #] "! L 	4QC89I	sR   
B, BAB	7B?	B, 	
B	B
B)$B, )B, ,
C6CCCc            	         Sn / n [        5        nUR                  5        nUR                  U 5        UR                  5       nU H!  nUR	                  US   US   US   S.5        M#     SSS5        SSS5        U$ ! , (       d  f       N= f! , (       d  f       U$ = f! [
         a  n[        SU 35        / s SnA$ SnAff = f)ug   
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   r[   r\   )r'   r   
CurrSymbolNzError al obtener las monedas: )r   ru   rv   r   r   rx   ry   )rz   
currenciesr{   ru   r   r|   r}   s          rC   get_currencies RecepcionCotizSQL.get_currencies   s    
 ]
	!T[[]fNN5)!??,D#"))-0VAVYZ[V\]_  $ # "  #] "!  	21#67I	sR   
B BA	A<*B2	B <
B
	B
BB B 
C)B>8C>Cc                    Sn/ n [        5        nUR                  5        nUR                  X5        UR                  5       nU HL  nUR	                  US   US   US   [        US   5      US   [        US   5      [        US   5      S	.5        MN     S
S
S
5        S
S
S
5        U$ ! , (       d  f       N= f! , (       d  f       U$ = f! [         a  n[        SU 35        / s S
nA$ S
nAff = f)u>   
Consulta Q_CostingDetail para obtener las líneas de costeo.
a  
            SELECT 
                CostingLine,
                PartNum,
                PartDescription,
                Qty,
                UOMCode,
                UnitPrice,
                Amount
            FROM Q_CostingDetail
            WHERE CostingID = (
                SELECT TOP 1 CostingID 
                FROM Q_CostingHead 
                WHERE CostingNum = ? 
                ORDER BY Version DESC
            )
            ORDER BY CostingLine ASC;
        r   r[   r\   r]   r^   r_   r`   )CostingLinePartNumPartDescriptionQtyUOMCode	UnitPriceAmountNz%Error al obtener detalles de costeo: r   )rY   rz   detailsr{   ru   r   r|   r}   s           rC   get_costing_details%RecepcionCotizSQL.get_costing_details   s    
$ 	!T[[]fNN56!??,D#+.q6'*1v/21v#(Q='*1v).s1v&+CFm(   $ # " N #] "! N 	9!=>I	sR   
C
 B8A4B'B8	C
 '
B5	1B88
CC
 C
 

C.C)#C.)C.datac                 
    SSK Jn  SSKJn  U R                  S5      nSn[	        5        nUR                  5        nUR                  XC5        UR                  5       nUS   nSn	UR                  X45        UR                  5       n
U
(       a  U
S   OSnU(       d   [        SU 35         S	S	S	5        S	S	S	5        g	US   nUS
   (       a  US
   OSnUR                  SU5        UR                  5       nUS   (       d  S
OUS   S
-   nU R                  S5      nUnU(       a8  UR                  SU5        UR                  5       nU(       a  US   (       a  US   n[        SU SU 35        [        SUS    S35        [        SUS    S35        [        SUS    S35        US   (       a  US   R                  5       OS	nUS   (       a  US   R                  5       OS	nUS   (       a  US   R                  5       OS	n0 SU_SU_SU_SU R                  S5      _SU R                  S5      _SU R                  S5      _SU R                  S5      _SUS    _S!US"   _S#US$   _S%US&   _S'US(   _S)US*   _S+US,   _S-US.   _S/US0   _S1U=(       d    S2_0 S3U=(       d    S4_S5U=(       d    S6_S7U R                  S8S5      _S9U R                  S:S5      _S;U R                  S<S5      _S=U_S>U_S?U R                  S@S5      _SAU_SBU_SCU R                  SDS
5      _SEU R                  SF/ 5      _SG[        U R                  SF/ 5      5      _SHUR                  " 5       R                  SI5      _SJUR                  " 5       R                  SK5      _SLUR                  " 5       R                  _SMSN_E0 SOSP_SQU R                  SQSR5      _SSU R                  SSST5      _SUU R                  SU5      _SVU R                  SV5      _SWU R                  SW5      _SXU R                  SX5      _SYU R                  SY5      _SZU R                  SZ5      _S[U R                  S[5      _S\U R                  S\5      _S]U R                  S]5      _S^U R                  S^5      _S_U R                  S_5      _S`U R                  S`5      _SaU R                  Sa5      _SbU R                  Sb5      _En[        ScUS1    35        U" Se0 UD6nUsS	S	S	5        sS	S	S	5        $ ! , (       d  f       O= f S	S	S	5        g	! , (       d  f       g	= f! [         a,  n[        SdU 35        SS	KnUR!                  5          S	nAg	S	nAff = f)fu_   
Genera HTML de vista previa de la cotización SIN guardar en BD.
Retorna el HTML renderizado.
r   )render_templater   r-   u  
                SELECT TOP 1
                    Q_CostingHead.CostingNum,
                    Q_CostingHead.Version,
                    
                    -- Cliente
                    Q_OpportunityCRM.CRM_ContactName,
                    Q_OpportunityCRM.CRM_ContactType,
                    Q_OpportunityCRM.CRM_OpportunityNumber,
                    Q_OpportunityCRM.CRM_ContactEmail,
                    Q_OpportunityCRM.CRM_ContactNumber,
                    Q_OpportunityCRM.CRM_ContactCity,
                    Q_OpportunityCRM.CRM_ContactState,
                    Q_OpportunityCRM.CRM_ContactCountry,
                    Q_OpportunityCRM.CRM_ContactAdress,
                    
                    -- ✅ El vendedor es el UserID de la oportunidad
                    TRIM(CONCAT(
                        ISNULL(Seller.FirstName, ''), ' ',
                        ISNULL(Seller.MiddleName, ''), ' ', 
                        ISNULL(Seller.LastName, ''), ' ',
                        ISNULL(Seller.SecondLastName, '')
                    )) AS VendedorNombre,
                    ISNULL(Seller.Email, '') AS VendedorEmail,
                    ISNULL(Seller.ContactPhone, '') AS VendedorTelefono,
                    Q_CostingHead.TaxCode

                    
                FROM Q_CostingHead
                
                INNER JOIN Q_OpportunityCRM 
                    ON Q_CostingHead.CRM_OpportunityID = Q_OpportunityCRM.CRM_OpportunityID
                
                -- ✅ JOIN directo: El vendedor es Q_OpportunityCRM.UserID
                LEFT JOIN Profiles AS Seller
                    ON Q_OpportunityCRM.UserID = Seller.UserID
                
                WHERE Q_CostingHead.CostingID = ?
            r   z
                        select TaxPercent
                        from Q_TaxRate
                        where TaxCode = ?
                    u   ❌ No se encontró CostingID: Nr[   m
                        SELECT MAX(Version) FROM Q_QuotationHead WHERE QuotationNum = ?
                    r'   zk
                            SELECT FrontES FROM Q_Currency WHERE CurrencyCode = ?
                        u   💱 Moneda: z -> u   🔍 DEBUG - VendedorNombre: 're   'u   🔍 DEBUG - VendedorEmail: 'rf   u    🔍 DEBUG - VendedorTelefono: 'rg   quotation_numversionr   caso_costeor;   r?   r@   rA   cliente_nombrer\   tipo_contactor]   oportunidad_crmr^   cliente_emailr_   cliente_telefonor`   cliente_ciudadra   cliente_estadorb   cliente_paisrc   cliente_direccionrd   vendedor_asignadozNo asignadovendedor_emailzventas@igsa.comvendedor_telefonozN/Aprecio_lista	SalePricedescuento_porcentajeDiscountPercentprecio_ofertar   impuesto_codigoimpuedesto_porcentajeprecio_totalTotalAmountmonedamoneda_codigofactor_sobrecostoOvercostFactorlineasQuotationLinestotal_lineasfecha_actualz%d/%m/%Yhora_actualz%H:%Mu   año_actualempresaIGSAempresa_completaz"Integradora de Servicios Avanzadosproyecto_nombrezPor definirproyecto_requerimientosNingunocaseSelectedcase1AnticipoPercentcase1FiniquitoPercentcase2AnticipoPercentcase2FrequencyTypecase2Periodicidadcase2Cantidadcase2CantidadPeriodicidadcase3FrequencyTypecase3Periodicidadcase3Cantidadcase3CantidadPeriodicidadcase4DiasFinanciamientocase5PlazoCreditoFlagu    ✅ Vendedor final en template: u#   ❌ Error al generar vista previa: )z*Emails/Ventas/Cotiz/PreviewCotizacion.html)flaskr   r   getr   ru   rv   rw   ry   striplennowstrftimeyearrx   	traceback	print_exc)r   r   r   r   rz   r{   ru   r|   taxCodequery2tax_rowtax_percentr   current_versionversion_resultnext_versioncurrency_codecurrency_namecurrency_resultvendedor_nombrer   r   template_datahtmlr}   r   s                             rC   generate_quotation_preview,RecepcionCotizSQL.generate_quotation_preview	  s   I	-)+.J&EV  !T[[]fNN55 //+C!"gGF
 NN6:6$oo/G07'!*QK ?
|LM## # "!( %(FM03Ac!fAO NN $&( &,__%6N,:1,=1>RSCTWXCXL %)HH^$<M$1M$ (*, +1//*;*q/A,;A,>MM-]OLM :3r7)1EF9#b'!DE<SWIQGH :=Rc"gmmodO8;BSW]]_TN;>r7B%R%'R% "<R% %j	R%
 &txx
';R% (/)BR% &txx'>R% 6txx@]7^R% )#a&R% (QR% *3q6R%  (Q!R%" +CF#R%$ )#a&%R%& )#a&'R%( 'A)R%* ,SW+R%0 ,_-M1R%2 ).*M<M3R%4 ,->-G%5R%: 'a(@;R%< /9JA0N=R%> ((A)>?R%@ *7AR%B 0CR%D '(BER%H !-IR%J (KR%P ,TXX6F-JQR%V !$((+;R"@WR%X 'DHH5Er,J(KYR%^ '(?(?
(K_R%` &x||~'>'>w'GaR%b &x||~':':cR%d "6eR%f +,PgR%l *4884E}+UmR%n 2488<UW`3aoR%r '(@sR%x /9O0PyR%z 0:Q1R{R%@ /9O0PAR%B -dhh7K.LCR%D ,TXX6I-JER%F (/)BGR%H 4TXX>Y5ZIR%N -dhh7K.LOR%P ,TXX6I-JQR%R (/)BSR%T 4TXX>Y5ZUR%Z 2488<U3V[R%` 0:Q1RaR%Mh <]K^=_<`ab*i[hiDa #] "!"]] "!!f  	7s;<!		se   )T( TA/S<+T3T( <P-S<)	T2	T( <
T
	TT( 
T%!T( %T( (
U2"UUc                     [        5        nUR                  5        nU R                  S5      nUR                  SU5        UR	                  5       nU(       d  SSS.sSSS5        sSSS5        $ US   nUR                  SU5        UR	                  5       nUS   (       d  S	OUS   S	-   nU S
U 3n[        SU 35        Sn	UR                  U	UUU R                  S5      U R                  S5      U R                  SS5      U R                  SS	5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S5      U R                  S 5      U R                  S!5      U R                  S"5      45        U R                  S#/ 5      n
S$nU
 H  nUR                  UUUR                  S%5      UR                  S&5      UR                  S'5      UR                  S(5      UR                  S)5      UR                  S*5      UR                  S+5      UR                  S5      4	5        M     UR                  5         [        S,U S-35        SSS5        S.S/WWS0.sSSS5        $ ! , (       d  f       N= f! , (       d  f       g= f! [         a&  n[        S1U 35        S[        U5      S.s SnA$ SnAff = f)2u   
Crea una nueva cotización en Q_QuotationHead y Q_QuotationDetail.
Envía notificación por correo al departamento de ingeniería.
r-   zf
                        SELECT CostingNum FROM Q_CostingHead WHERE CostingID = ?
                    FzCostingID no encontrado)successerrorNr   r   r[   -u   Creando cotización: a  
                        INSERT INTO Q_QuotationHead (
                            QuotationNum,
                            Version,
                            CaseCost,
                            SalePrice,
                            DiscountPercent,
                            OvercostFactor,
                            Amount,
                            TaxCode,
                            TotalAmount,
                            CurrencyCode,
                            Active,
                            caseSelected,
                            case1AnticipoPercent,
                            case1FiniquitoPercent,
                            case2AnticipoPercent,
                            case2FrequencyType,
                            case2Periodicidad,
                            case2Cantidad,
                            case2CantidadPeriodicidad,
                            case3FrequencyType,
                            case3Periodicidad,
                            case3Cantidad,
                            case3CantidadPeriodicidad,
                            case4DiasFinanciamiento,
                            case5PlazoCreditoFlag
                        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                    r;   r   r   r   r   r&   r   r'   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   a  
                        INSERT INTO Q_QuotationDetail (
                            QuotationID,
                            QuotationLine,
                            CostingLineID,
                            PartNum,
                            PartDescription,
                            Qty,
                            UOMCode,
                            UnitPrice,
                            Amount
                        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
                    QuotationLineCostingLineIDr   r   r   r   r      Cotización z creada exitosamente en BDTu   Cotización creada exitosamente)r   messageQuotationIDVersionu   Error al crear cotización: )	r   ru   r   rv   rw   ry   commitrx   rQ   )r   r{   ru   r   costing_resultr   r   r   quotation_idinsert_head_queryquotation_linesinsert_detail_queryliner}   s                 rC   create_quotation"RecepcionCotizSQL.create_quotation  s,   @	7!T[[]f!%+!6J NN $#% &,__%6N)+0;TU #] "! %31$5M NN $&( &,__%6N'5a'8anQ>ORS>SG&3_AgY#?L1,@A)%< NN#4%,-!2A6!115*+/00!78!89!78!56!451!<=!56!451!<=!:;!8937 : '+hh/?&DO+' !0':( HH_5 HH_5 HHY/ HH%67 HHUO HHY/ HH[1 HHX.
= 
 !0 KKML6PQRg #l  $@#/&	m "!"] "!z  	7045$s1v66	7sd   
M  L/?L	L/%	M  /JLL/	M  
L,	(L//
L=9M  =M   
M0
M+%M0+M0r   c                 .    SSK Jn  U" 5        nUR                  5        nUR                  SU 5        UR	                  5       nU(       ao  US   (       a  US   R                  5       OSUS   (       a  US   R                  5       OSUS   (       a  US   R                  5       OSS.sSSS5        sSSS5        $  SSS5        SSS5        SSSS.$ ! , (       d  f       N= f! , (       d  f       N%= f! [         a  n[        SU 35         SnANESnAff = f)	u!   Obtiene información del vendedorr   r
   a  
                        SELECT TOP 1
                            TRIM(CONCAT(
                                ISNULL(Seller.FirstName, ''), ' ',
                                ISNULL(Seller.MiddleName, ''), ' ', 
                                ISNULL(Seller.LastName, ''), ' ',
                                ISNULL(Seller.SecondLastName, '')
                            )) AS VendedorNombre,
                            ISNULL(Seller.Email, '') AS VendedorEmail,
                            ISNULL(Seller.ContactPhone, '') AS VendedorTelefono
                            
                        FROM Q_CostingHead
                        INNER JOIN Q_OpportunityCRM 
                            ON Q_CostingHead.CRM_OpportunityID = Q_OpportunityCRM.CRM_OpportunityID
                        LEFT JOIN Profiles AS Seller
                            ON Q_OpportunityCRM.UserID = Seller.UserID
                        WHERE Q_CostingHead.CostingID = ?
                    Nr[   r\   )nombreemailtelefonou+   ⚠️ Error al obtener info del vendedor: )Consultas_SQL.conexionr   ru   rv   rw   r   rx   ry   )r   r   r{   ru   r|   r}   s         rC   get_seller_info!RecepcionCotizSQL.get_seller_infoe  s     	E=!T[[]fNN $" $#%& !//+C8;Ac!fllnD7:1vSV\\^4:=a&Ad - #] "!, + # "> 4@@= #] "!8  	E?sCDD	EsX   C2 C!BC&	C!/	C2 :C!C2 
C	C!!
C/+C2 /C2 2
D<DDrU   N)rL   rM   rN   rO   rP   staticmethodrR   r   r   r~   r   r   rQ   r	   rI   r   r   r   rS   r   r   r  rT   rU   rF   rC   rW   rW   `   s&   cMS MXF^=_ M M^ tDeCJ&7!789  & Dc3h0  & ) )d ) )Z N N# N Nd E7t E7 E7 E7P $AC $AD $A $ArF   rW   c                     [        U [        5      (       a  [        U 5      $ [        U [        5      (       a  U R	                  5       $ [        S[        U 5      R                   S35      e)zG
Convierte objetos Decimal y datetime a formatos compatibles con JSON.
zObject of type z is not JSON serializable)
isinstancer   rI   r   	isoformat	TypeErrortyperL   )objs    rC   json_serializerr    sT     #wSz#x  }}
od3i&8&8%99RS
TTrF   rG   c            	      x   Sn [        5       nU(       d  [        R                  S5        g UR                  5       nUR	                  U 5        UR
                   Vs/ s H  o3S   PM	     nnUR                  5       nU(       d<  [        R                  S5         UR                  5         [        R                  S5        gU Vs/ s H  n[        [        XF5      5      PM     nnU H  nUR                  5        Hv  u  p[        U
[        5      (       a  U
R                  5       X'   M.  [        U
[         5      (       a  [#        U
5      X'   MR  [        U
[$        5      (       d  Mi  [%        U
5      X'   Mx     M     UUR                  5         [        R                  S5        $ s  snf s  snf ! [&        R(                   a'  n[        R                  S[+        U5       35        e SnAf[,         a'  n[        R                  S[+        U5       35        e SnAff = f! UR                  5         [        R                  S5        f = f)	u  
Obtiene todos los registros activos del catálogo Q_TermsType y los devuelve
como una lista de diccionarios serializables a JSON.

Returns:
    List[Dict]: Lista de registros de términos y condiciones.
    None: Si no se encuentran registros o ocurre un error.
a  
        SELECT
            TermsTypeID,
            FrontES,
            FrontEN,
            Active,
            createdAt,
            CreatedBy,
            UpdatedAt,
            UpdatedBy
        FROM Q_TermsType
        WHERE Active = 1
        ORDER BY TermsTypeID ASC;
    u9   ❌ No se pudo establecer conexión con la base de datos.Nr   u:   ⚠️ No se encontraron registros activos en Q_TermsType.u*   🔒 Conexión a la base de datos cerrada.u    Error SQL al obtener términos: z(Error inesperado en get_TermsType_JSON: )r   loggerr   ru   rv   descriptionr   warningcloseinforS   zipitemsr  r   r	  r   rI   boolpyodbcErrorrQ   rx   )rz   r{   ru   colcolumnsr   r|   resultsrkeyvaluer}   s               rC   get_TermsType_JSONr    s   E DPQ!Bu%+%7%78%7cq6%78 NNWX0 	

@A- 7;;ds4G)*d; Aggi
eX.."__.AFw//"5\AFt,,!%[AF (   	

@A= 9 < << 7Ax@A ?AxHI 	

@AsZ   /F% F(.F% =F% F A<F% F% 
F% %H9"GH("H

HH 'H9cotizacion_idc           	         U (       d  [         R                  S5        gSnSn[        5       nU(       d  [        S5      e UR	                  5       nUR                  X5        UR                   Vs/ s H  oUS   PM	     nnUR                  5       nU(       dG  [         R                  SU  35         U(       a&  UR                  5         [         R                  S5        gg[        [        Xg5      5      nUR                  X 5        UR                   Vs/ s H  oUS   PM	     n	nUR                  5       n
U
 Vs/ s H  n[        [        X5      5      PM     nnUUS	.nS
US   ;   a3  US   S
   n[        U[        5      (       a  UR!                  5       US   S
'   US   R#                  5        H.  u  nn[        U[$        5      (       d  M  ['        U5      US   U'   M0     US    HB  nUR#                  5        H+  u  nn[        U[$        5      (       d  M  ['        U5      UU'   M-     MD     UU(       a&  UR                  5         [         R                  S5        $ $ s  snf s  snf s  snf ! [(        R*                   a*  n[         R                  SU  S[-        U5       35        e SnAf[.         a'  n[         R                  S[-        U5       35        e SnAff = f! U(       a&  UR                  5         [         R                  S5        f f = f)u  
Busca el encabezado y el detalle de una cotización usando su ID primario,
y los devuelve en un diccionario con tipos de datos serializables a JSON.

Args:
    cotizacion_id (str): El ID primario de la cotización (ej. "1001-1").

Returns:
    Un diccionario con la estructura de QuotationHead y QuotationDetail,
    con tipos de datos serializables a JSON, o None si no se encuentra.
u(   Se proporcionó un cotizacion_id vacío.Na  
        SELECT
            QuotationID, QuotationDate, QuotationNum, Version, SalePrice,
            DiscountPercent, Amount, TaxCode, TotalAmount, CurrencyCode,
            DeliveryTime, TermsAndConditions
        FROM Q_QuotationHead
        WHERE QuotationID = ?;
    a  
        SELECT
            QuotationLineID, QuotationID, QuotationLine, CostingLineID,
            PartNum, PartDescription, Qty, UOMCode, UnitPrice, Amount
        FROM Q_QuotationDetail
        WHERE QuotationID = ?
        ORDER BY QuotationLine ASC;
    u5   No se pudo establecer conexión con la base de datos.r   u6   No se encontró encabezado de cotización para el ID: u%   Conexión a la base de datos cerrada.)QuotationHeadQuotationDetailQuotationDater"  r#  u.   Error de base de datos al buscar cotización 'z': z5Error inesperado en get_Quote_JSON_BussinessCentral: )r  r   r   ConnectionErrorru   rv   r  rw   r  r  r  rS   r  r   r  r   r	  r  r   rI   r  r  rQ   rx   )r   
query_headquery_detailr{   ru   columncolumns_headrow_headquotation_head_datacolumns_detailrows_detailr|   quotation_detail_data
final_datadate_objr  r  r   r}   s                      rC   get_Quote_JSON_BussinessCentralr1    s    ?@JL DUVV<A 	z1060B0BC0Bfq	0BC??$NNSTaSbcd` JJLKK?@ ] #3|#>? 	|3282D2DE2D)2DEoo'KV W;Cc.&>!?; W 14

 j99!/2?CH(H--?G?Q?Q?S
?+O< %_5;;=JC%))38<
?+C0 > 01D"jjl
UeW-- %eDI + 2
  JJLKK?@ k D F !X@ << Em_TWX[\]X^W_`a LSQRVHUV JJLKK?@ sm   /I" .I<1I" 3I" II" 3IA/I" AI" I" I" "K6%JK("K

KK /Lc                     U R                  S5      u  pUR                  5       n[        UR                  5       5      nSn[        5       nU(       d  [        S5      e U   UR                  5       nUR                  X1U45        UR                   Vs/ s H  ofS   PM	     nnUR                  5       nU(       d:  [        R                  SU  35         SSS5        U(       a  UR                  5         gg0 n	/ n
U Hl  n[        [        X{5      5      nU	(       d$  U Vs0 s H  oS;  d  M
  XU   _M     n	nX	S	'   XS
'   U
R!                  US   US   US   US   US   US   S.5        Mn     U	sSSS5        U(       a  UR                  5         $ $ ! [         a    [        R                  SU  35         gf = fs  snf s  snf ! , (       d  f       Op= f! ["        R$                   a'  n[        R                  S['        U5       35        e SnAf[(         a'  n[        R                  S['        U5       35        e SnAff = f U(       a  UR                  5         gg! U(       a  UR                  5         f f = f)u   
Busca los datos de la oportunidad, las líneas de ingeniería y el estado.

Args:
    cotizacion_id (str): ID de la oportunidad (Ej: 123456-1)

Returns:
    Dict: Datos de la oportunidad y las líneas o None.
r   u$   Formato de cotizacion_id inválido: Nu  
        SELECT
            T1.CRM_OpportunityNumber,
            T1.Version,
            T1.CRM_ContactName,
            T1.CRM_ContactEmail,
            T1.Status AS StatusVenta,
            -- Asumimos una tabla de estado de ingeniería
            T2.StatusIngenieria, 
            T3.Partnum,
            T3.Description,
            T3.Quantity,
            T3.UnitPriceIngenieria, -- Precio que puso Ingeniería
            T3.DiscountVenta,       -- Descuento que puede modificar Venta
            T3.FinalPrice,
            -- Campos financieros ya calculados (si existen)
            T1.PrecioLista,
            T1.PrecioVentaIVA,
            T1.TiempoEntrega,
            T1.UnidadTiempo,
            T1.TerminosIngenieria -- Términos de Ingeniería
        FROM Q_OpportunityCRM T1
        LEFT JOIN Q_QuotationHead T2 ON T1.CRM_OpportunityID = T2.CRM_OpportunityID 
        LEFT JOIN Q_QuotationLines T3 ON T2.QuotationID = T3.QuotationID 
        WHERE 
            T1.CRM_OpportunityNumber = ? AND T1.Version = ? AND T1.Active = 1
            AND T2.StatusIngenieria IS NOT NULL -- Solo cotizaciones que han pasado por ingeniería
        ORDER BY T3.LineNum ASC
    u4   No se pudo establecer conexión con la base de datosr   u-   No se encontraron datos para Cotización ID: )PartnumDescriptionQuantityUnitPriceIngenieriaDiscountVenta
FinalPricer   r   r3  r4  r5  r6  r7  r8  u.   Error de base de datos al buscar cotización: z0Error inesperado en buscar_cotizacion_completa: )splitr   rR   
ValueErrorr  r   r   r%  ru   rv   r  r   r  r  rS   r  r   r  r  rQ   rx   )r   	op_numberr   rz   r{   ru   r(  r  r   headerlinesr|   r   kr}   s                  rC   buscar_cotizacion_completar?  A  sO   *005	OO%	gmmo&E< D']^^+[[]FNN5g"67/5/A/AB/AVay/AGB??$D!N}o^_ T 4= FEC-.26  a$Q  D`  ;`jaaj$F  a.;?+',8$ #I#'#6 $Z 0+/0E+F%)/%:"&|"4  $ C TT 4g  ;M?KLZ C a' TF << Ec!fXNO GAxPQM T 444s   <F G 2F=F32F=G 2(F=	F8'	F809F=)	G "F0/F03
F==
GG 
I G H8""HH8"H33H88I I/r   user_idc                    U(       d  SSS.$  SSK Jn  U" U5      n[        R                  S[	        U5       SU  SU 35        SS	S.$ ! [
         a9  n[        R                  S
[        U5       35        S[        U5      S.s SnA$ SnAff = f)z?Actualiza campos editables (ej. Descuento) en Q_QuotationLines.Tu   No hay líneas para actualizarr   r   r[   obtener_nombre_usuariozActualizando u    líneas para z por u   Líneas actualizadasu,   Error al actualizar líneas de cotización: FN)CotizEspSolicitudSQLrD  r  r  r   rx   r   rQ   )r   r   r@  rD  	user_namer}   s         rC   actualizar_lineas_cotizacionrG    s     ,LMM5@*73	 	mCK=}oUS\R]^_  ,BCC 5CCF8LM SV445s   9A 
B.B BBfinancierosc           	      
   Sn[        5       nU(       d  SSS.$  SSKJn  U" U5      nU   UR                  5       nUR	                  UUS   US   US	   UU 45        UR                  5         UR                  S
:X  a&  SSS.sSSS5        U(       a  UR                  5         $ $ [        R                  SU  35        SS0sSSS5        U(       a  UR                  5         $ $ ! , (       d  f       Ob= f! [        R                   aH  n[        R                  S[        U5       35        SSS.s SnAU(       a  UR                  5         $ $ SnAff = f U(       a  UR                  5         gg! U(       a  UR                  5         f f = f)uI   Actualiza la sección financiera en Q_OpportunityCRM (o Q_QuotationHead).a1  
        UPDATE Q_OpportunityCRM
        SET 
            DiscountPorcentaje = ?,
            IncludesIVA = ?,
            PrecioVentaIVA = ?,
            UpdatedBy = ?,
            UpdatedAt = GETDATE()
        WHERE CRM_OpportunityID = ? -- Asumiendo que el ID de la oportunidad es el cotizacion_id
    F   Error de conexión a BDrB  r[   rC  	descuentoincluye_ivaprecio_final_con_ivar   u8   Oportunidad no encontrada para actualización financieraNz$Datos financieros actualizados para r   Tz'Error de BD al actualizar financieros: Error de base de datosr   rE  rD  ru   rv   r   rowcountr  r  r  r  r  r   rQ   )	r   rH  r@  rz   r{   rD  rF  ru   r}   s	            rC   actualizar_calculo_financierorQ    sO   	E DE6OPP@*73	[[]FNN5K(M*23#  KKM!##(5op T( 4 KK>}oNOt$ T( 4) T  << G>s1vhGH -EFF4	G! ( 444_   C/ AC?	C/ !C<	C/ 
C,(C/ +E( ,C/ /E%E(E)E( EE( (Ftiempo_condicionesc           	      
   Sn[        5       nU(       d  SSS.$  SSKJn  U" U5      nU   UR                  5       nUR	                  UUS   US   US	   UU 45        UR                  5         UR                  S
:X  a&  SSS.sSSS5        U(       a  UR                  5         $ $ [        R                  SU  35        SS0sSSS5        U(       a  UR                  5         $ $ ! , (       d  f       Ob= f! [        R                   aH  n[        R                  S[        U5       35        SSS.s SnAU(       a  UR                  5         $ $ SnAff = f U(       a  UR                  5         gg! U(       a  UR                  5         f f = f)uM   Actualiza el tiempo de entrega y los términos técnicos en Q_OpportunityCRM.u  
        UPDATE Q_OpportunityCRM
        SET 
            TiempoEntrega = ?,
            UnidadTiempo = ?,
            TerminosVenta = ?, -- Nuevo campo para términos de Venta
            UpdatedBy = ?,
            UpdatedAt = GETDATE()
        WHERE CRM_OpportunityID = ?
    FrJ  rB  r[   rC  tiempo_ejecucionunidad_tiempoterminos_ventar   u<   Oportunidad no encontrada para actualización de condicionesNz'Tiempo y condiciones actualizados para r   Tz0Error de BD al actualizar tiempo y condiciones: rN  rO  )	r   rS  r@  rz   r{   rD  rF  ru   r}   s	            rC   actualizar_tiempo_y_condicionesrX    sP   	E DE6OPP@*73	[[]FNN5"#56"?3"#34#  KKM!##(5st T( 4 KKA-QRt$ T( 4) T  << GGAxPQ -EFF4	G! ( 444rR  r   c                      [        X5      n[        R                  SU  SU 35        SUS.$ ! [         a9  n[        R	                  S[        U5       35        S[        U5      S.s SnA$ SnAff = f)	u   
Marca el estado final de la cotización, genera el PDF y registra el evento.

Nota: La generación de PDF con Puppeteer/Node.js debería llamarse aquí.
r   z0 marcada como ENVIADA_A_CLIENTE y PDF generado: T)r   pdf_urlu.   Error al finalizar cotización y generar PDF: FrB  N)generar_pdf_final_cotizacionr  r  rx   r   rQ   )r   r@  r   rZ  r}   s        rC   finalizar_cotizacion_y_enviarr\    ss    5 /}C
 	l=/1abiajklG44 5Ec!fXNO SV445s   *- 
A0.A+%A0+A0c                     SU  S3$ )uI   Simula la generación de PDF final (debería llamar a Node.js/Puppeteer).z*https://sycelephant.com/static/pdfs/cotiz/z
_final.pdfrU   )r   r   s     rC   r[  r[  1  s     8jQQrF   )r   decimalr   r  loggingtypingr   r   r   r	   r  r   	getLoggerr  r   rW   r  r  rQ   r1  r?  rR   rG  rQ  rX  r\  r[  rU   rF   rC   <module>rb     sO       . . 1			5	6O
 O
djA jA\U=BHT$Z0 =B@bA3 bA8D> bALbc bhtn bN5 5T$Z 5RU 5Z^ 5.) )4 )RU )Z^ )\(3 (D ([^ (cg (Z5 5s 5$ 5SW 5.R R4 RC RrF   