+
    /Si)                        ^ RI H t  ^ RIHt ^ RIt^ RIt^ RIHtHtHtH	t	 ^ RI
Ht ]P                  ! R4      t ! R R4      t ! R	 R
4      tR tR R ltR R ltR R ltR R ltR R ltR R ltR R ltR R ltR# )    datetime)DecimalN)OptionalListDictUnionget_connectionrecepcion_cotizacion_sqlc                   L   a  ] tR t^t o RtRV 3R lR lltV 3R lR ltRtV tR# )	OpportunityAndCostingDTOuI   DTO para la información unificada de Oportunidad y Encabezado de Costeo.Nc          8         < V ^8  d   QhRS[ RS[ RS[ RS[ RS[ RS[ RS[ RS[ R	S[ R
S[ RS[ RS[ RS[ RS[ RS[ RS[RS[RS[RS[RS[ RS[ RS[RS[ RS[ RS[ RS[ RS[ RS[ /# )   
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_FrontEN)strfloatint)format__classdict__s   "kC:\Users\victor.barrera\Documents\proyectos\elepV3\Elep\src\Consultas_SQL\Ventas\Cotiz\RecepcionCotizSQL.py__annotate__%OpportunityAndCostingDTO.__annotate__   s    *5 *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  *5    c                |   Wn         W n        W0n        W@n        WPn        W`n        Wpn        Wn        Wn        Wn	        Wn
        Wn        Wn        Wn        Wn        VV n        VV n        VV n        VV n        VV n        V3V n        VV n        V3V n        V3V n        V3V n        V3V n        V3V n        VV n        R # )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   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&r2   __init__!OpportunityAndCostingDTO.__init__   s     $%;"//'?$!3"5/!3"5*F'- 1 1!,*"6,(+I+J(,x(M!2!3!2!3"4"5"4r5   c                    < V ^8  d   QhRS[ /# r   returndict)r0   r1   s   "r2   r3   r4   >   s     
 
 
r5   c                   / RV P                   bRV P                  bRV P                  bRV P                  bRV P                  bRV P
                  bRV P                  bRV P                  bR	V P                  bR
V P                  bRV P                  bRV P                  bRV P                  bRV P                  bRV P                  bR\        V P                   4      bR\        V P"                  4      bR\        V P$                  4      RV P&                  RV P(                  RV P*                  ^ ,          RV P,                  e   \        V P,                  4      MRRV P.                  ^ ,          RV P0                  ^ ,          RV P2                  ^ ,          RV P4                  ^ ,          RV P6                  ^ ,          RV P8                  /C# )z2Convierte el objeto a un diccionario serializable.r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   rJ   rK   r&   Nr'   r(   r)   r*   r+   r,   )r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   r.   rF   rG   rH   rI   rJ   rK   r&   r'   r(   r)   r*   r+   r,   )rL   s   &r2   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#
$ !%(?(?"@T//4++)4+K+KA+ND<O<O<[eD$7$78aeQD--a0!7!7!:!7!7!: $"9"9!"< $"9"99
 	
r5   )r;   r<   r>   r=   r@   rD   rA   r9   r?   rC   r:   rB   r8   rE   r7   r(   rH   r&   r,   r+   r*   r)   rI   rJ   rF   rG   r'   rK   )
NNNNNNNNNN)	__name__
__module____qualname____firstlineno____doc__rM   rU   __static_attributes____classdictcell__r1   s   @r2   r   r      s     S*5 *5Z
 
r5   r   c                      a  ] tR t^`t o Rt]V 3R lR l4       t]V 3R lR l4       t]V 3R lR l4       t]V 3R lR	 l4       t	]V 3R
 lR l4       t
]V 3R lR l4       t]V 3R lR l4       tRtV tR# )RecepcionCotizSQLuY   Clase de servicio para manejar la lógica de recepción de datos de costeo y oportunidad.c                6   < V ^8  d   QhRS[ RS[S[,          /# r   costing_numrQ   )r/   r   r   )r0   r1   s   "r2   r3   RecepcionCotizSQL.__annotate__d   s%     M MS MXF^=_ Mr5   c           	        Rp \        4       ;_uu_ 4       pVP                  4       ;_uu_ 4       pVP                  W4       VP                  4       pRRR4       X'       Ed,   \	        R / RV^ ,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bR	V^,          bR
V^,          bRV^,          bRV^	,          bRV^
,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          b uuRRR4       #  RRR4       R#   + '       g   i     ELP; i  + '       g   i     R# ; i  \
         d   p\        RT 24        Rp?R# Rp?ii ; i)!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,   z#Error al obtener datos unificados:  )r   cursorexecutefetchoner   	Exceptionprint)rc   queryconnrg   rowes   &     r2   get_unified_data_by_costing_num1RecepcionCotizSQL.get_unified_data_by_costing_numc   s>   -\	!!T[[]]fNN56 //+C # 3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;<	s^   G  F,"F	F,"D F,
G  F,G  F)#	F,,F=	7G  =G   G$GG$c                \   < V ^8  d   QhRS[ S[S[S[S[S[3,          3,          ,          /# rP   )r   r   r-   r	   r.   )r0   r1   s   "r2   r3   rd      s,      tDeCJ&7!789 r5   c                    Rp . p \        4       ;_uu_ 4       pVP                  4       ;_uu_ 4       pVP                  V 4       VP                  4       pV FA  pVP	                  RV^ ,          RV^,          R\        V^,          4      RV^,          /4       KC  	  RRR4       RRR4       V#   + '       g   i     L; i  + '       g   i     T# ; i  \         d   p\        RT 24       . u Rp?# Rp?ii ; i)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'   FrontES	TaxAmountr(   Nz Error al obtener los impuestos: r   rg   rh   fetchallappendr.   rj   rk   )rl   taxesrm   rg   rowsrn   ro   s          r2   	get_taxesRecepcionCotizSQL.get_taxes   s    
 g	!!T[[]]fNN5)!??,D#iQCFKY^FZ$%3SV&= >  $ # " L #] "! L 	4QC89I	sR   C B?A)B,	B?"	C ,B<7B??C	
C C C8C3-C83C8c                F   < V ^8  d   QhRS[ S[S[S[3,          ,          /# rP   )r   r   r-   )r0   r1   s   "r2   r3   rd      s!      Dc3h0 r5   c                    Rp . p \        4       ;_uu_ 4       pVP                  4       ;_uu_ 4       pVP                  V 4       VP                  4       pV F/  pVP	                  RV^ ,          RV^,          RV^,          /4       K1  	  RRR4       RRR4       V#   + '       g   i     L; i  + '       g   i     T# ; i  \
         d   p\        RT 24       . u Rp?# Rp?ii ; i)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(   rt   
CurrSymbolNzError al obtener las monedas: )r   rg   rh   rw   rx   rj   rk   )rl   
currenciesrm   rg   rz   rn   ro   s          r2   get_currencies RecepcionCotizSQL.get_currencies   s    
 ]
	!!T[[]]fNN5)!??,D#"))+SVYAVYZ[V\]_  $ # "  #] "!  	21#67I	sR   C B-AB	B-	C B*%B--B>	8C >C C&C!C&!C&c                6   < V ^8  d   QhRS[ RS[S[,          /# rb   )r/   r   r   )r0   r1   s   "r2   r3   rd      s     ) ) )d )r5   c                P   Rp. p \        4       ;_uu_ 4       pVP                  4       ;_uu_ 4       pVP                  W4       VP                  4       pV Fn  pVP	                  RV^ ,          RV^,          RV^,          R\        V^,          4      RV^,          R\        V^,          4      R\        V^,          4      /4       Kp  	  R	R	R	4       R	R	R	4       V#   + '       g   i     L; i  + '       g   i     T# ; i  \         d   p\        R
T 24       . u R	p?# R	p?ii ; i)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;
        CostingLinePartNumPartDescriptionQtyUOMCode	UnitPriceAmountNz%Error al obtener detalles de costeo: rv   )rc   rl   detailsrm   rg   rz   rn   ro   s   &       r2   get_costing_details%RecepcionCotizSQL.get_costing_details   s    
$ 	!!T[[]]fNN56!??,D#)3q6%s1v-s1v!5Q=%s1v's1v$eCFm(   $ # " N #] "! N 	9!=>I	sR   D  C,BC	C,	D  C)$C,,C=	7D  =D   D%D D% D%c                &   < V ^8  d   QhRS[ RS[/# r   datarQ   )rS   r-   )r0   r1   s   "r2   r3   rd   
  s     N N N# Nr5   c                    ^ RI Hp ^ RIHp V P                  R4      pRp\	        4       ;_uu_ 4       pVP                  4       ;_uu_ 4       pVP                  WC4       VP                  4       pV^,          pRp	VP                  W34       VP                  4       p
V
'       d
   V
^ ,          M^ pV'       g"   \        RV 24        RRR4       RRR4       R# V^ ,          pV^,          '       d
   V^,          M^ pVP                  RV4       VP                  4       pV^ ,          '       g   ^MV^ ,          ^,           pV P                  R	4      pTpV'       dC   VP                  R
V4       VP                  4       pV'       d   V^ ,          '       d
   V^ ,          p\        RV RV 24       \        RV^,           R24       \        RV^,           R24       \        RV^,           R24       V^,          '       d   V^,          P                  4       MRpV^,          '       d   V^,          P                  4       MRpV^,          '       d   V^,          P                  4       MRp/ RVbRVbRVbRV P                  R4      bRV P                  R4      bRV P                  R4      bRV P                  R4      bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bRV^,          bR V^	,          bR!V^
,          bR"T;'       g    R#b/ R$T;'       g    R%bR&T;'       g    R'bR(V P                  R)^ 4      bR*V P                  R+^ 4      bR,V P                  R-^ 4      bR.VbR/VbR0V P                  R1^ 4      bR2VbR3VbR4V P                  R5^4      bR6V P                  R7. 4      bR8\        V P                  R7. 4      4      bR9VP                  ! 4       P                  R:4      bR;VP                  ! 4       P                  R<4      bR=VP                  ! 4       P                  bR>R?bC/ R@RAbRBV P                  RBRC4      bRDV P                  RDRE4      bRFV P                  RF4      bRGV P                  RG4      bRHV P                  RH4      bRIV P                  RI4      bRJV P                  RJ4      bRKV P                  RK4      bRLV P                  RL4      bRMV P                  RM4      bRNV P                  RN4      bROV P                  RO4      bRPV P                  RP4      bRQV P                  RQ4      bRRV P                  RR4      bRSV P                  RS4      bCp\        RTVR",           24       V! RV/ VB pVuuRRR4       uuRRR4       #   + '       g   i     M; i RRR4       R#   + '       g   i     R# ; i  \         d.   p\        RUT 24       ^ RIpTP!                  4         Rp?R# Rp?ii ; i)Wu_   
Genera HTML de vista previa de la cotización SIN guardar en BD.
Retorna el HTML renderizado.
)render_templater   r7   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 = ?
            z
                        select TaxPercent
                        from Q_TaxRate
                        where TaxCode = ?
                    u   ❌ No se encontró CostingID: Nm
                        SELECT MAX(Version) FROM Q_QuotationHead WHERE QuotationNum = ?
                    r(   zk
                            SELECT FrontES FROM Q_Currency WHERE CurrencyCode = ?
                        u   💱 Moneda: z -> u   🔍 DEBUG - VendedorNombre: ''u   🔍 DEBUG - VendedorEmail: 'u    🔍 DEBUG - VendedorTelefono: 'quotation_numversionr   caso_costeorE   rI   rJ   rK   cliente_nombretipo_contactooportunidad_crmcliente_emailcliente_telefonocliente_ciudadcliente_estadocliente_paiscliente_direccion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   rg   rh   ri   rk   striplennowstrftimeyearrj   	traceback	print_exc)r   r   r   r   rl   rm   rg   rn   taxCodequery2tax_rowtax_percentr   current_versionversion_resultnext_versioncurrency_codecurrency_namecurrency_resultvendedor_nombrer   r   template_datahtmlro   r   s   &                         r2   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,;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;>r77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-M1R%2 ).*M*M<M3R%4 ,->-G-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;<!		s   1W V.A)V	6V	V.W V	/;V	+,V	)V	V	BV	$'V	CV	V	)V	6IV	;
V.
W V V.$W .V?	9W ?W W:"W55W:c                &   < V ^8  d   QhRS[ RS[ /# r   rR   )r0   r1   s   "r2   r3   rd     s     E7 E7t E7 E7r5   c           !     F    \        4       ;_uu_ 4       pVP                  4       ;_uu_ 4       pV P                  R4      pVP                  RV4       VP	                  4       pV'       g   RRRR/uuRRR4       uuRRR4       # V^ ,          pVP                  RV4       VP	                  4       pV^ ,          '       g   ^MV^ ,          ^,           pV R	V 2p\        R
V 24       Rp	VP                  V	VVV P                  R4      V P                  R4      V P                  R^ 4      V P                  R^4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      V P                  R 4      V P                  R!4      34       V P                  R". 4      p
R#pV
 F  pVP                  VVVP                  R$4      VP                  R%4      VP                  R&4      VP                  R'4      VP                  R(4      VP                  R)4      VP                  R*4      VP                  R4      3	4       K  	  VP                  4        \        R+V R,24       RRR4       RR-R.R/R0XR1X/uuRRR4       #   + '       g   i     L$; i  + '       g   i     R# ; i  \         d(   p\        R2T 24       RRR\        T4      /u Rp?# Rp?ii ; i)3u   
Crea una nueva cotización en Q_QuotationHead y Q_QuotationDetail.
Envía notificación por correo al departamento de ingeniería.
r7   zf
                        SELECT CostingNum FROM Q_CostingHead WHERE CostingID = ?
                    successFerrorzCostingID no encontradoNr   -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, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                    rE   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 BDTmessageu   Cotización creada exitosamenteQuotationIDVersionu   Error al crear cotización: )	r   rg   r   rh   ri   rk   commitrj   r-   )r   rm   rg   r   costing_resultr   r   r   quotation_idinsert_head_queryquotation_linesinsert_detail_querylinero   s   &             r2   create_quotation"RecepcionCotizSQL.create_quotation  sH   @	7!!T[[]]f!%+!6J NN $#% &,__%6N) )5';TU #] "! %31$5M NN $&( &,__%6N'5a'8'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 t@!<w	m "!"] "!!z  	7045ugs1v66	7sk   M. MAM	.
M8
M. 9M	=I.M	+M<
M. MMM+	%M. +M. .N 9NN N c                &   < V ^8  d   QhRS[ RS[/# )r   r   rQ   )r-   rS   )r0   r1   s   "r2   r3   rd   f  s     $A $AC $AD $Ar5   c                    ^ RI Hp V! 4       ;_uu_ 4       pVP                  4       ;_uu_ 4       pVP                  RV 4       VP	                  4       pV'       d   RV^ ,          '       d   V^ ,          P                  4       MRRV^,          '       d   V^,          P                  4       MRRV^,          '       d   V^,          P                  4       MR/uuRRR4       uuRRR4       #  RRR4       RRR4       RRRRRR/#   + '       g   i     L ; i  + '       g   i     L+; i  \         d   p\        RT 24        Rp?LLRp?ii ; i)u!   Obtiene información del vendedorr
   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 = ?
                    nombreNemailtelefonou+   ⚠️ Error al obtener info del vendedor: )Consultas_SQL.conexionr   rg   rh   ri   r   rj   rk   )r   r   rm   rg   rn   ro   s   &     r2   get_seller_info!RecepcionCotizSQL.get_seller_infoe  s    	E=!!T[[]]fNN $" $#%& !//+C$Ac!fllnD#s1vvSV\\^4&#a&&Ad - #] "!, + # "> $z4@@= #] "!8  	E?sCDD	Esi   D( D:D	+'D	'D	;D	
D
D( *D2D( DDD%	 D( %D( (E3EErf   N)rW   rX   rY   rZ   r[   staticmethodrp   r{   r   r   r   r   r   r\   r]   r^   s   @r2   r`   r`   `   s     cM M^  &  & ) )Z N Nd E7 E7P $A $Ar5   r`   c                    \        V \        4      '       d   \        V 4      # \        V \        4      '       d   V P	                  4       # \        R\        V 4      P                   R24      h)zG
Convierte objetos Decimal y datetime a formatos compatibles con JSON.
zObject of type z is not JSON serializable)
isinstancer   r.   r   	isoformat	TypeErrortyperW   )objs   &r2   json_serializerr    sT     #wSz#x  }}
od3i&8&8%99RS
TTr5   c                P    V ^8  d   QhR\         \        \        ,          ,          /# rP   )r   r   r   )r0   s   "r2   r3   r3     s     =B =BHT$Z0 =Br5   c            	        Rp \        4       pV'       g   \        P                  R4       R#  VP                  4       pVP	                  V 4       VP
                   Uu. uF  q3^ ,          NK  	  ppVP                  4       pV'       g>   \        P                  R4        VP                  4        \        P                  R4       R# V Uu. uF  p\        \        WF4      4      NK  	  ppV F  pVP                  4        Fy  w  r\        V
\        4      '       d   V
P                  4       W&   K/  \        V
\         4      '       d   \#        V
4      W&   KT  \        V
\$        4      '       g   Kl  \%        V
4      W&   K{  	  K  	  VVP                  4        \        P                  R4       # u upi u upi   \&        P(                   d(   p\        P                  R\+        T4       24       h Rp?i\,         d(   p\        P                  R\+        T4       24       h Rp?ii ; i  TP                  4        \        P                  R4       i ; i)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.Nu:   ⚠️ 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   rg   rh   descriptionrw   warningcloseinforS   zipitemsr  r   r  r   r.   boolpyodbcErrorr-   rj   )rl   rm   rg   colcolumnsrz   rn   resultsrkeyvaluero   s               r2   get_TermsType_JSONr    s   E DPQ!Bu%+%7%78%7cq66%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 	

@As`   /F. F$-/F. F. F)%A>F. (F. $
F. .H"G%%H2H3"HHH 'Ic                F    V ^8  d   QhR\         R\        \        ,          /# r   cotizacion_idrQ   r-   r   r   )r0   s   "r2   r3   r3     s&     bA bA3 bA8D> bAr5   c           	     j   V '       g   \         P                  R4       R# RpRp\        4       pV'       g   \        R4      h VP	                  4       pVP                  W4       VP                   Uu. uF  qU^ ,          NK  	  ppVP                  4       pV'       gK   \         P                  RV  24        V'       d(   VP                  4        \         P                  R4       R# R# \        \        Wg4      4      pVP                  W 4       VP                   Uu. uF  qU^ ,          NK  	  p	pVP                  4       p
V
 Uu. uF  p\        \        W4      4      NK  	  ppRVR	V/pR
VR,          9   dA   VR,          R
,          p\        V\        4      '       d   VP!                  4       VR,          R
&   VR,          P#                  4        F3  w  pp\        V\$        4      '       g   K  \'        V4      VR,          V&   K5  	  VR	,           FC  pVP#                  4        F,  w  pp\        V\$        4      '       g   K  \'        V4      VV&   K.  	  KE  	  TV'       d'   VP                  4        \         P                  R4       # # u upi u upi u upi   \(        P*                   d+   p\         P                  RT  R\-        T4       24       h Rp?i\.         d(   p\         P                  R\-        T4       24       h Rp?ii ; i  T'       d'   TP                  4        \         P                  R4       i i ; i)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.u6   No se encontró encabezado de cotización para el ID: u%   Conexión a la base de datos cerrada.QuotationHeadQuotationDetailQuotationDateu.   Error de base de datos al buscar cotización 'z': z5Error inesperado en get_Quote_JSON_BussinessCentral: )r	  r   r   ConnectionErrorrg   rh   r
  ri   r  r  r  rS   r  rw   r  r   r  r  r   r.   r  r  r-   rj   )r  
query_headquery_detailrm   rg   columncolumns_headrow_headquotation_head_datacolumns_detailrows_detailrn   quotation_detail_data
final_datadate_objr  r  r   ro   s   &                  r2   get_Quote_JSON_BussinessCentralr.    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 04

 j99!/2?CH(H--?G?Q?Q?S
?+O< %_5;;=JC%))38<
?+C0 > 011D"jjl
UeW-- %eDI + 2
  JJLKK?@ k D F !X@ << Em_TWX[\]X^W_`a LSQRVHUV JJLKK?@ st   /J 1J2J &3J J*J  JBJ (AJ ;J J K?%%K

K?K?"K::K??L 0L2c                F    V ^8  d   QhR\         R\        \        ,          /# r  r  )r0   s   "r2   r3   r3   A  s"     b bc bhtn br5   c                `    V P                  R4      w  rVP                  4       p\        VP                  4       4      pRp\        4       pT'       g   \        R4      h T;_uu_ 4        TP                  4       pTP                  Y1T34       TP                   Uu. uF  qf^ ,          NK  	  ppTP                  4       pT'       g>   \        P                  RT  24        RRR4       T'       d   TP                  4        R# R# / p	. p
T F  p\        \        Y{4      4      pT	'       g)   T Uu/ uF  qR9  g   K  YT,          bK  	  p	pY	R&   YR&   T
P!                  RTR,          RTR,          R	TR	,          R
TR
,          RTR,          RTR,          /4       K  	  T	uuRRR4       T'       d   TP                  4        # #   \         d    \        P                  RT  24        R# i ; iu upi u upi   + '       g   i     Mr; i  \"        P$                   d(   p\        P                  R\'        T4       24       h Rp?i\(         d(   p\        P                  R\'        T4       24       h Rp?ii ; i T'       d   TP                  4        R# R#   T'       d   TP                  4        i i ; i)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 datosu-   No se encontraron datos para Cotización ID: PartnumDescriptionQuantityUnitPriceIngenieriaDiscountVenta
FinalPricer  r   u.   Error de base de datos al buscar cotización: z0Error inesperado en buscar_cotizacion_completa: )r1  r2  r3  r4  r5  r6  )splitr   r/   
ValueErrorr	  r   r   r"  rg   rh   r
  rw   r  r  rS   r  rx   r  r  r-   rj   )r  	op_numberr   rl   rm   rg   r%  r  rz   headerlinesrn   r   kro   s   &              r2   buscar_cotizacion_completar=  A  s_   *005	OO%	gmmo&E< D']^^+T[[]FNN5g"67/5/A/AB/AVayy/AGB??$D!N}o^_ T 4= FEC-.26  a$Q  D`  ;`jaaj$F  a.;?+',8$ tI!4#6Z 0)40E+F#T/%: $|"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? 
H (2G3G)+3G3H )G3+G.
8G.
AG3
H ?#G&%G&)
G33H	>H J H I2"H==I2
I2"I--I22J J-c                ^    V ^8  d   QhR\         R\        \        ,          R\        R\        /# )r   r  r   user_idrQ   )r-   r   r   r/   )r0   s   "r2   r3   r3     s.     5 5 5T$Z 5RU 5Z^ 5r5   c                &   V'       g   RRRR/#  ^RI Hp V! V4      p\        P                  R\	        V4       RV  RV 24       RRRR	/#   \
         d;   p\        P                  R
\        T4       24       RRR\        T4      /u Rp?# Rp?ii ; i)z?Actualiza campos editables (ej. Descuento) en Q_QuotationLines.r   Tr   u   No hay líneas para actualizarobtener_nombre_usuariozActualizando u    líneas para z por u   Líneas actualizadasu,   Error al actualizar líneas de cotización: FN)CotizEspSolicitudSQLrB  r	  r  r   rj   r   r-   )r  r   r?  rB  	user_namero   s   &&&   r2   actualizar_lineas_cotizacionrE    s     4,LMM5@*73	 	mCK=}oUS\R]^_ 4,BCC 5CCF8LM5)SV445s   :A B/BBBc                H    V ^8  d   QhR\         R\        R\        R\        /# )r   r  financierosr?  rQ   r-   r   r/   )r0   s   "r2   r3   r3     s*     ) ) )4 )RU )Z^ )r5   c           
     T   Rp\        4       pV'       g   RRRR/#  ^RIHp V! V4      pT;_uu_ 4        VP                  4       pVP	                  VVR,          VR,          VR	,          VV 34       VP                  4        VP                  ^ 8X  d*   RRRR
/uuRRR4       V'       d   VP                  4        # # \        P                  RV  24       RR/uuRRR4       V'       d   VP                  4        # #   + '       g   i     Me; i  \        P                   dK   p\        P                  R\        T4       24       RRRR/u Rp?T'       d   TP                  4        # # Rp?ii ; i T'       d   TP                  4        R# R#   T'       d   TP                  4        i i ; i)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
    r   Fr      Error de conexión a BDrA  	descuentoincluye_ivaprecio_final_con_ivau8   Oportunidad no encontrada para actualización financieraNz$Datos financieros actualizados para Tz'Error de BD al actualizar financieros: Error de base de datosr   rC  rB  rg   rh   r   rowcountr  r	  r  r  r  r   r-   )	r  rG  r?  rl   rm   rB  rD  rg   ro   s	   &&&      r2   actualizar_calculo_financierorQ    s]   	E DE96OPP@*73	T[[]FNN5K(M*23#  KKM!#!5)5op T( 4 KK>}oNOt$ T( 4) T  << G>s1vhGH5)-EFF4	G! ( 444_   D A#C:
D ;C:
D :D
	D 	F 
D E,"&E'E,	F 'E,,F F'c                H    V ^8  d   QhR\         R\        R\        R\        /# )r   r  tiempo_condicionesr?  rQ   rH  )r0   s   "r2   r3   r3     s*     ( (3 (D ([^ (cg (r5   c           
     T   Rp\        4       pV'       g   RRRR/#  ^RIHp V! V4      pT;_uu_ 4        VP                  4       pVP	                  VVR,          VR,          VR	,          VV 34       VP                  4        VP                  ^ 8X  d*   RRRR
/uuRRR4       V'       d   VP                  4        # # \        P                  RV  24       RR/uuRRR4       V'       d   VP                  4        # #   + '       g   i     Me; i  \        P                   dK   p\        P                  R\        T4       24       RRRR/u Rp?T'       d   TP                  4        # # Rp?ii ; i T'       d   TP                  4        R# R#   T'       d   TP                  4        i i ; i)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 = ?
    r   Fr   rJ  rA  tiempo_ejecucionunidad_tiempoterminos_ventau<   Oportunidad no encontrada para actualización de condicionesNz'Tiempo y condiciones actualizados para Tz0Error de BD al actualizar tiempo y condiciones: rN  rO  )	r  rT  r?  rl   rm   rB  rD  rg   ro   s	   &&&      r2   actualizar_tiempo_y_condicionesrY    s^   	E DE96OPP@*73	T[[]FNN5"#56"?3"#34#  KKM!#!5)5st T( 4 KKA-QRt$ T( 4) T  << GGAxPQ5)-EFF4	G! ( 444rR  c                H    V ^8  d   QhR\         R\        R\        R\        /# )r   r  r?  r   rQ   )r-   r/   r   )r0   s   "r2   r3   r3     s)     5 5 5s 5$ 5SW 5r5   c                     \        W4      p\        P                  RV  RV 24       RRRV/#   \         d;   p\        P	                  R\        T4       24       RRR\        T4      /u R	p?# R	p?ii ; i)
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: r   Tpdf_urlu.   Error al finalizar cotización y generar PDF: Fr   N)generar_pdf_final_cotizacionr	  r  rj   r   r-   )r  r?  r   r\  ro   s   &&&  r2   finalizar_cotizacion_y_enviarr^    s{    5 /}C
 	l=/1abiajkl4G44 5Ec!fXNO5)SV445s   +. A3/A.(A3.A3c                <    V ^8  d   QhR\         R\        R\         /# )r   r  r   rQ   )r-   r   )r0   s   "r2   r3   r3   1  s&     R R R4 RC Rr5   c                    RV  R2# )uI   Simula la generación de PDF final (debería llamar a Node.js/Puppeteer).z*https://sycelephant.com/static/pdfs/cotiz/z
_final.pdfrf   )r  r   s   &&r2   r]  r]  1  s     8jQQr5   )r   decimalr   r  loggingtypingr   r   r   r	   r   r   	getLoggerr	  r   r`   r  r  r.  r=  rE  rQ  rY  r^  r]  rf   r5   r2   <module>re     s        . . 1			5	6O
 O
djA jA\U=B@bALbN5.)\(Z5.Rr5   