# Archivo: Cotizador.py
# Ruta: src\App\Ventas_Module\VentasEUA\Cotizador.py
# Lenguaje: Python con Flask

from flask import current_app
from flask import jsonify, request, redirect, url_for, session, current_app, render_template, flash 
from datetime import datetime
import os
import glob
import uuid
import subprocess
from decimal import Decimal 
import requests  # Para hacer las solicitudes HTTP a la API de Microsoft Graph
import requests
from App.Security_Module.UserPassword import send_activation_email
from flask_mail import Message
from tempfile import NamedTemporaryFile
from config import Host, SCHEME, Productivo
from datetime import datetime, date

from werkzeug.datastructures import FileStorage
from App.Subir_Archivo import subir_archivo_ftp_desde_request
from Consultas_SQL.Ventas.VentasEUA.CotizadorSQL import (
    get_fueltype, get_kw_by_fuel, get_engine_brands, get_alternator_brands, get_voltages, 
    get_certifications, get_breaker_catalog, get_protection_types, 
    get_control_brands, get_control_models, get_preheater_voltages, get_battery_chargers,
    get_enclosure_types, get_enclosure_materials, get_enclosure_lights_ac, get_enclosure_lights_dc, 
    get_enclosure_space_heaters, get_enclosure_load_centers,
    get_estop_catalog, get_spring_catalog,
    get_tank_capacity_catalog, get_tank_type_catalog, get_spill_containment_catalog,
    get_warranty_catalog, get_testing_catalog,
    save_quote,
    get_quote_data, get_genset_data, update_genset_pricing,
    get_breaker_data, get_protection_data, update_breaker_pricing, update_protection_pricing,
    get_breaker_option_data, update_breaker_option_pricing,
    get_controller_data, update_controller_pricing, get_preheater_data, update_preheater_pricing, get_battery_charger_data, update_battery_charger_pricing,
    get_controller_option_qty_data, update_dse2157_pricing, update_dse2548_pricing, update_comap_dse2157_pricing, update_comap_dse2548_pricing,
    get_controller_option_data, update_controller_option_pricing,
    get_enclosure_data, get_light_data, get_space_heater_data, get_load_center_data, update_enclosure_pricing, update_enclosure_component_pricing,
    get_enclosure_option_qty_data, get_enclosure_option_data, update_enclosure_option_pricing,
    get_spring_isolator_data, get_estop_data, update_estop_pricing, update_spring_isolator_pricing,
    get_accessory_option_data, update_accessory_option_pricing,
    get_tank_data, get_spill_containment_data, get_tank_option_data, update_tank_pricing, update_tank_option_pricing,
    get_warranty_data, get_testing_data, update_warranty_pricing, update_testing_pricing,
    get_Definitive_quote_data, get_genset_model, get_frecuency,
    get_seller_info, get_profile_info,update_RoutePDF,get_RoutePDF, get_countrys, get_discount_country_value, update_commercial_country_values,
    getAll_StopButtonEnclosure, getAll_louvers_in,getAll_louvers_out
)

from App.api.controller import CZE_Quotes_Controller
from App.api.services import CZE_Quotes_Service,StopButtonEnclosureOptions_Service
# ----------------------------------------------------------Endpoints-start----------------------------------------------------------




def get_optionsimput(app,mail):

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/fuel-types', methods=['GET'])
    def get_fuel_types():
        try:
            fuel_types = get_fueltype()
            return jsonify(fuel_types), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500
    

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/StopButtonEnclosure', methods=['GET'])
    def end_getAll_StopButtonEnclosure():
        try:
            fuel_types = getAll_StopButtonEnclosure()
            return jsonify(fuel_types), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500


    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/load_louvers_in', methods=['GET'])
    def end_getAll_louvers_in():
        try:
            fuel_types = getAll_louvers_in()
            return jsonify(fuel_types), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500
    

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/load_louvers_out', methods=['GET'])
    def end_getAll_louvers_out():
        try:
            fuel_types = getAll_louvers_out()
            return jsonify(fuel_types), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500
    

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/capacidades/<fuel_type>', methods=['GET'])
    def get_capacidades(fuel_type):
        try:
            capacidades = get_kw_by_fuel(fuel_type)
            return jsonify(capacidades), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500


    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/engine-brands/<fuel_type>/<kw_output>', methods=['GET'])
    def get_engine_brands_route(fuel_type, kw_output):
        try:
            brands = get_engine_brands(fuel_type, kw_output)
            return jsonify(brands), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500
    

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/alternator-brands/<fuel_type>/<kw_output>/<engine_brand_id>', methods=['GET'])
    def get_alternator_brands_route(fuel_type, kw_output, engine_brand_id):
        try:
            brands = get_alternator_brands(fuel_type, kw_output, engine_brand_id)
            return jsonify(brands), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500
    
    
    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/voltages/<fuel_type>/<kw_output>/<engine_brand_id>/<alternator_brand_id>')
    def get_voltages_route(fuel_type, kw_output, engine_brand_id, alternator_brand_id):
        try:
            voltages = get_voltages(fuel_type, kw_output, engine_brand_id, alternator_brand_id)
            return jsonify(voltages), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500


    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/certifications/<fuel_type>/<kw_output>/<engine_brand_id>/<alternator_brand_id>/<voltage_id>')
    def get_certifications_route(fuel_type, kw_output, engine_brand_id, alternator_brand_id, voltage_id):
        try:
            certifications = get_certifications(fuel_type, kw_output, engine_brand_id, alternator_brand_id, voltage_id)
            return jsonify(certifications)
        except Exception as e:
            return jsonify({"error": str(e)}), 500


    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/breaker-options')
    def get_breaker_catalog_route():
        try:
            breakers = get_breaker_catalog()
            return jsonify(breakers)  # Ya no necesitamos transformar los datos
        except Exception as e:
            return jsonify({"error": str(e)}), 500


    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/protection-types/<breaker_type>')
    def get_protection_types_route(breaker_type):
        try:
            protections = get_protection_types(breaker_type)
            return jsonify(protections)  # Ya no necesitamos transformar los datos
        except Exception as e:
            return jsonify({"error": str(e)}), 500   
    

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/control-brands/<fuel_type>/<kw_output>/<engine_brand_id>/<alternator_brand_id>/<voltage_id>/<certification_id>')
    def get_control_brands_route(fuel_type, kw_output, engine_brand_id, alternator_brand_id, voltage_id, certification_id):
        try:
            brands = get_control_brands(fuel_type, kw_output, engine_brand_id, alternator_brand_id, voltage_id, certification_id)
            return jsonify(brands)
        except Exception as e:
            print(f"Error obteniendo marcas de control: {e}")
            return jsonify({"error": str(e)}), 500
    

    # En Cotizador.py, modificar la ruta:
    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/control-models/<control_brand_id>')
    def get_control_models_route(control_brand_id):
        try:
            models = get_control_models(control_brand_id)
            return jsonify(models)
        except Exception as e:
            return jsonify({"error": str(e)}), 500
        
    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/preheater-voltages')
    def get_preheater_voltages_route():
        try:
            voltages = get_preheater_voltages()
            return jsonify(voltages)
        except Exception as e:
            print(f"Error obteniendo voltajes de precalentador: {e}")
            return jsonify({"error": str(e)}), 500
        
    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/battery-chargers')
    def get_battery_chargers_route():
        try:
            chargers = get_battery_chargers()
            return jsonify(chargers)
        except Exception as e:
            print(f"Error obteniendo cargadores de batería: {e}")
            return jsonify({"error": str(e)}), 500
        
    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/enclosure-types/<fuel_type>/<kw_output>/<certification_id>')
    def get_enclosure_types_route(fuel_type, kw_output, certification_id):
        try:
            types = get_enclosure_types(fuel_type, kw_output, certification_id)
            return jsonify(types)
        except Exception as e:
            return jsonify({"error": str(e)}), 500

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/enclosure-materials/<fuel_type>/<kw_output>/<certification_id>/<enclosure_type>')
    def get_enclosure_materials_route(fuel_type, kw_output, certification_id, enclosure_type):
        try:
            materials = get_enclosure_materials(fuel_type, kw_output, certification_id, enclosure_type)
            return jsonify(materials)
        except Exception as e:
            return jsonify({"error": str(e)}), 500
        
    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/enclosure-lights-ac', methods=['GET'])
    def get_enclosure_lights_ac_route():
        try:
            lights = get_enclosure_lights_ac()
            return jsonify(lights)
        except Exception as e:
            print(f"Error obteniendo luces AC de caseta: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/enclosure-lights-dc', methods=['GET'])
    def get_enclosure_lights_dc_route():
        try:
            lights = get_enclosure_lights_dc()
            return jsonify(lights)
        except Exception as e:
            print(f"Error obteniendo luces DC de caseta: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/enclosure-space-heaters', methods=['GET'])
    def get_enclosure_space_heaters_route():
        try:
            heaters = get_enclosure_space_heaters()
            return jsonify(heaters)
        except Exception as e:
            print(f"Error obteniendo calentadores de espacio: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/enclosure-load-centers', methods=['GET'])
    def get_enclosure_load_centers_route():
        try:
            centers = get_enclosure_load_centers()
            return jsonify(centers)
        except Exception as e:
            print(f"Error obteniendo centros de carga: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/additional-estop', methods=['GET'])
    def get_estop_catalog_route():
        try:
            options = get_estop_catalog()
            return jsonify(options), 200
        except Exception as e:
            print(f"Error en ruta de paro de emergencia: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/additional-spring', methods=['GET'])
    def get_spring_catalog_route():
        try:
            options = get_spring_catalog()
            return jsonify(options), 200
        except Exception as e:
            print(f"Error en ruta de resorte de aislador: {e}")
            return jsonify({"error": str(e)}), 500
        
    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/tank-capacity/<kw_output>')
    def get_tank_capacity_route(kw_output):
        try:
            capacities = get_tank_capacity_catalog(kw_output)
            return jsonify(capacities)
        except Exception as e:
            return jsonify({"error": str(e)}), 500

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/tank-type/<kw_output>/<tank_autonomy>')
    def get_tank_type_route(kw_output, tank_autonomy):
        try:
            types = get_tank_type_catalog(kw_output, tank_autonomy)
            return jsonify(types)
        except Exception as e:
            return jsonify({"error": str(e)}), 500

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/spill-containment', methods=['GET'])
    def get_spill_containment_route():
        try:
            options = get_spill_containment_catalog()
            return jsonify(options), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500
        
    # nuevas ---------------------------------------------------------------  
    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/countrys', methods=['GET'])
    def get_countrys_route():
        try:
            options = get_countrys()
            return jsonify(options), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/warranty-options', methods=['GET'])
    def get_warranty_options_route():
        try:
            options = get_warranty_catalog()
            return jsonify(options), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500

    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/testing-options/<kw_output>')
    def get_testing_options_route(kw_output):
        try:
            options = get_testing_catalog(kw_output)
            return jsonify(options)
        except Exception as e:
            return jsonify({"error": str(e)}), 500
    
    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/get-profile-info', methods=['GET'])
    def get_profile_info_route():
        try:
            # Obtener el ID del usuario de la sesión
            user_id = session.get('user_id')
            if not user_id:
                return jsonify({"error": "Usuario no autenticado"}), 401
                
            profile_info = get_profile_info(user_id)
            if not profile_info:
                return jsonify({"error": "Perfil no encontrado"}), 404
                
            # Si es distribuidor, obtener información del vendedor
            if profile_info.get("RequestTypeID") in ["DISEUA", "DISCAN"] and profile_info.get("SellerUserID"):
                seller_info = get_seller_info(profile_info["SellerUserID"])
                if seller_info:
                    profile_info["SellerInfo"] = seller_info
                    
            return jsonify(profile_info), 200
        except Exception as e:
            print(f"Error obteniendo información del perfil: {e}")
            return jsonify({"error": str(e)}), 500      
        
    @app.route('/Ventas/Ventas_EUA/Cotizador_EUA/save-quote', methods=['POST'])
    def save_quote_route():
        try:
            data = request.get_json()
            print("Datos recibidos para guardar cotización:")
            print(data)
            
            quote_id = save_quote(data)
            
            pricing_Genset(quote_id)

            return jsonify({
                "success": True,
                "quote_id": quote_id,
                "message": "Cotización guardada exitosamente"
            })
                    
        except Exception as e:
            print(f"Error al guardar cotización: {str(e)}")
            return jsonify({
                "success": False,
                "error": str(e)
            }), 500
    

    def pricing_Genset(quote_id):
        """Procesa todos los precios y fichas técnicas para una cotización."""
        try:
            # Obtener datos de la cotización
            quote_data = get_quote_data(quote_id)
            if not quote_data:
                raise Exception("Cotización no encontrada")

            # --------------- Seccion General del Genset --------

            # Obtener datos de la planta generadora
            genset_data = get_genset_data(
                quote_data[0],  # FuelTypeIDBack
                quote_data[1],  # KWOutput
                quote_data[2],  # EngineBrandID
                quote_data[3],  # AlternatorBrandID
                quote_data[4],  # VoltageID
                quote_data[5],  # CertificationID
                quote_data[6],  # ControllerBrandID
                quote_data[7],  # QtyGenset
                quote_data[177] # Descuento
            )

            # Guardar los precios de la planta generadora
            if genset_data:
                # Actualizar precios del generador
                update_genset_pricing(
                    quote_id,
                    genset_data['cost_id'],
                    genset_data['unit_price'],
                    genset_data['tech_sheet'],
                    genset_data['Genset_PriceTot'],
                    genset_data['EngineModel'],
                    genset_data['EngineTSheet'],
                    genset_data['E_Tier'],
                    genset_data['E_Rpm'],
                    genset_data['E_Power'],
                    genset_data['E_NumberOfCylinder'],
                    genset_data['E_Aspiration'],
                    genset_data['E_Governor_type'],
                    genset_data['E_Control_voltage'],
                    genset_data['E_Battery_type'],
                    genset_data['E_Hotstart_model'],
                    genset_data['E_RadiatorTemp'],
                    genset_data['AlternatorModel'],
                    genset_data['AlternatorTSheet'],
                    genset_data['A_Powerfactor'],
                    genset_data['A_Insulation_System'],
                    genset_data['A_Control_System'],
                    genset_data['A_Protection'],
                    genset_data['A_AvrModel'],
                    genset_data['A_Voltage_Regulation'],
                    genset_data['A_Class_temp_rise']            
                )


            qty_genset = quote_data[7]  # QtyGenset
            kw_output = quote_data[1] 
            Discount = ((100 - quote_data[177]) / 100 ) # Descuento
            
            # ///// Seccion de Interruptores /////
            # Calculamos el precio del los Breakers1, 2 y 3; guardamos su ficha técnica asi como el precio total considerando la cantidad de Genset
            breaker_start_index = 8  # Índice donde comienzan los Item_breaker
            protection_start_index = 11  # Índice donde comienzan los Item_Proyection_t

            for i in range(3):  # Para los 3 breakers
                # Verificar si hay breaker seleccionado
                if quote_data[breaker_start_index + i] != "Seleccione una opción":
                    breaker_data = get_breaker_data(quote_data[breaker_start_index + i], qty_genset, Discount)
                    if breaker_data:
                        update_breaker_pricing(quote_id, i + 1, breaker_data)
                # Verificar si hay protección seleccionada
                if quote_data[protection_start_index + i] != "Seleccione un modelo de interrptor":
                    protection_data = get_protection_data(quote_data[protection_start_index + i], qty_genset, Discount)
                    if protection_data:
                        update_protection_pricing(quote_id, i + 1, protection_data)

            # Calculamos el precio de los Selectbox de Si/No de lasseccion de los Breakers1, 2 y 3; guardamos su ficha técnica asi como el precio total considerando la cantidad de Genset
            breaker_options = { # [índice_item, índice_descripción]
                'sunt_t': [(14, 15), (26, 27), (38, 39)],  # Para breakers 1, 2 y 3
                'sunt_w': [(16, 17), (28, 29), (40, 41)],
                'gfi': [(18, 19), (30, 31), (42, 43)],
                'aux_c': [(20, 21), (32, 33), (44, 45)],
                'breaker_l': [(22, 23), (34, 35), (46, 47)],
                'motorized': [(24, 25), (36, 37), (48, 49)]
            }

            for breaker_idx in range(3): # Para cada breaker (0-2 para breakers 1-3)
                # Para cada tipo de opción
                for option_type, indices_list in breaker_options.items():
                    item_idx, desc_idx = indices_list[breaker_idx]
                    item_value = quote_data[item_idx]
                    desc_value = quote_data[desc_idx]
                    # Verificar si la opción está seleccionada
                    if desc_value != "No":
                        option_data = get_breaker_option_data(item_value, qty_genset, Discount)
                        if option_data:
                            update_breaker_option_pricing(
                                quote_id,
                                breaker_idx + 1,  # Convertir 0-2 a 1-3
                                option_type,
                                option_data
                            )

            # ///// Seccion de Control /////
            # Calculamos el precio del control y guardamos su ficha técnica asi como el precio total considerando la cantidad de Genset
            if quote_data[50] != "Selecciona la marca de control":  # Item_controller
                controller_data = get_controller_data(quote_data[50], qty_genset, Discount)
                if controller_data:
                    update_controller_pricing(quote_id, controller_data)
            
            # Calculamos el precio del precalentador y guardamos su ficha técnica asi como el precio total considerando la cantidad de Genset
            if quote_data[52] != "Seleccione una opción":  # Item_CtrlVotlOper
                preheater_data = get_preheater_data(quote_data[52], qty_genset, Discount)
                if preheater_data:
                    update_preheater_pricing(quote_id, preheater_data)
            
            # Calculamos el precio del cargador de batería y guardamos su ficha técnica asi como el precio total considerando la cantidad de Genset
            if quote_data[54] != "Seleccione una opción":  # Item_BateryCharger
                charger_data = get_battery_charger_data(quote_data[54], qty_genset, Discount)
                if charger_data:
                    update_battery_charger_pricing(quote_id, charger_data)
            
            # Calculamos el precio de DSE2157 y guardamos su ficha técnica asi como el precio total considerando la cantidad de Genset
            a56 =quote_data[56]
            a58 =quote_data[58]
            if quote_data[57] != "No":  # DSE2157
                option_data = get_controller_option_qty_data(
                    quote_data[56],  # Item_DSE2157
                    qty_genset,
                    a58,   # QtyDSE2157
                    Discount
                )
                if option_data:
                    update_dse2157_pricing(quote_id, option_data)
            
            # Calculamos el precio de DSE2548 y guardamos su ficha técnica asi como el precio total considerando la cantidad de Genset
            if quote_data[60] != "No":  # DSE2548
                option_data = get_controller_option_qty_data(
                    quote_data[59],  # Item_DSE2548
                    qty_genset,
                    quote_data[61],   # QtyDSE2548
                    Discount
                )
                if option_data:
                    update_dse2548_pricing(quote_id, option_data)
            
            # Calculamos el precio de ComapDSE2157 y guardamos su ficha técnica asi como el precio total considerando la cantidad de Genset
            if quote_data[63] != "No":  # ComapDSE2157
                option_data = get_controller_option_qty_data(
                    quote_data[62],  # Item_ComapDSE2157
                    qty_genset,
                    quote_data[64],   # QtyComapDSE2157
                    Discount
                )
                if option_data:
                    update_comap_dse2157_pricing(quote_id, option_data)
            
            # Calculamos el precio de ComapDSE2548 y guardamos su ficha técnica asi como el precio total considerando la cantidad de Genset
            if quote_data[66] != "No":  # ComapDSE2548
                option_data = get_controller_option_qty_data(
                    quote_data[65],  # Item_ComapDSE2548
                    qty_genset,
                    quote_data[67],   # QtyComapDSE2548
                    Discount
                )
                if option_data:
                    update_comap_dse2548_pricing(quote_id, option_data)
                    
            # Calculamos el precio de las opciones de control y guardamos su ficha técnica asi como el precio total considerando la cantidad de Genset
            options = [ # [tipo, item_index, description_index
                ('comap_dse890', 68, 69),
                ('panel_heater', 70, 71),
                ('remote_display', 72, 73),
                ('antena', 74, 75),
                ('dse890', 76, 77),

                ('panel_heaterCMP', 178, 179),
                ('remote_displayCMP', 180, 181),
                ('antenaCMP', 182, 183),

            ]
            
            for option_type, item_idx, desc_idx in options:
                if quote_data[desc_idx] != "No":
                    option_data = get_controller_option_data(
                        quote_data[item_idx],
                        qty_genset,
                        Discount
                    )
                    if option_data:
                        update_controller_option_pricing(quote_id, option_type, option_data)
                        
            # ///// Seccion de la Caseta /////        
            # Procesar caseta principal
            enclosure_data = get_enclosure_data(
                quote_data[0],   # FuelTypeIDBack
                quote_data[1],   # KWOutput
                quote_data[5],   # CertificationID
                quote_data[78],  # Item_Enclosuree_type
                quote_data[79],  # Item_Eclousure_Mat
                qty_genset,
                Discount
            )
            if enclosure_data:
                update_enclosure_pricing(quote_id, enclosure_data)
            
            # Procesar luz AC
            if quote_data[80] != "Seleccione una opción":  # Item_Enclosure_ligthAC
                light_ac_data = get_light_data(
                    quote_data[80],  # Item_Enclosure_ligthAC
                    qty_genset,
                    quote_data[82],  # QtylightAC
                    Discount,
                    is_ac=True,
                )
                if light_ac_data:
                    update_enclosure_component_pricing(quote_id, 'light_ac', light_ac_data)
            
            # Procesar luz DC
            if quote_data[83] != "Seleccione una opción":  # Item_Enclosure_ligthDC
                light_dc_data = get_light_data(
                    quote_data[83],  # Item_Enclosure_ligthDC
                    qty_genset,
                    quote_data[85],  # QtylightDC
                    Discount,
                    is_ac=False
                )
                if light_dc_data:
                    update_enclosure_component_pricing(quote_id, 'light_dc', light_dc_data)
            
            # Procesar calentador de espacio
            if quote_data[86] != "Seleccione una opción":  # Item_Enclosure_SHeater
                heater_data = get_space_heater_data(
                    quote_data[86],  # Item_Enclosure_SHeater
                    qty_genset,
                    quote_data[88],   # QtySpaceHeater
                    Discount
                )
                if heater_data:
                    update_enclosure_component_pricing(quote_id, 'space_heater', heater_data)
            
            # Procesar centro de carga
            if quote_data[89] != "Seleccione una opción":  # Item_Enclosure_LCenter
                center_data = get_load_center_data(
                    quote_data[89],  # Item_Enclosure_LCenter
                    qty_genset,
                    Discount
                )
                if center_data:
                    update_enclosure_component_pricing(quote_id, 'load_center', center_data)
            
            # Opciones con cantidad propia
            qty_options = [
                ('gfci', 91, 92, 93),          # (tipo, item_index, desc_index, qty_index)
                ('receptable', 94, 95, 96),
                #('stopButtonEnclosure', 186, 187, 188) # StopButtonEnclosure
            ]

            stop_id:str = quote_data[186]  # Item_StopButtonEnclosure
            if stop_id != None:
                czeService = CZE_Quotes_Service.CZE_Quotes_Service()
                czeService.updateQuote_stopButtonEnclosure(quote_id)

            
            louvers_in = quote_data[190]  # Item_louvers_in
            if louvers_in != None:
                louversService = CZE_Quotes_Service.CZE_Quotes_Service()
                louversService.update_quote_louvers_in(quote_id)


            louvers_out = quote_data[192]  # Item_louvers_out
            if louvers_out != None:
                louversService = CZE_Quotes_Service.CZE_Quotes_Service()
                louversService.update_quote_louvers_out(quote_id)


            for option_type, item_idx, desc_idx, qty_idx in qty_options:
                if quote_data[desc_idx] != "No":
                    option_data = get_enclosure_option_qty_data(
                        quote_data[item_idx],
                        qty_genset,
                        quote_data[qty_idx],
                        Discount
                    )
                    if option_data:
                        update_enclosure_option_pricing(quote_id, option_type, option_data)
            
            # Opciones sin cantidad propia
            simple_options = [
                ('prewire', 97, 98),           # (tipo, item_index, desc_index)
                ('autolouvers', 99, 100),
                ('receptautolouvers', 101, 102),
                ('openingEnclousure', 184, 185)  # OpeningEnclosure
            ]
            
            for option_type, item_idx, desc_idx in simple_options:
                if quote_data[desc_idx] != "No":
                    option_data = get_enclosure_option_data(
                        quote_data[item_idx],
                        qty_genset,
                        Discount
                    )
                    if option_data:
                        update_enclosure_option_pricing(quote_id, option_type, option_data)
            
            # ///// Seccion de Accesorios adicionales ///// 
            # Procesar E-Stop
            if quote_data[103] != "Seleccione una opción":  # Item_AddAccesory_Estop
                estop_data = get_estop_data(
                    quote_data[103],  # Item_AddAccesory_Estop
                    qty_genset,
                    quote_data[105],   # QtyEStop
                    Discount
                )
                if estop_data:
                    update_estop_pricing(quote_id, estop_data)
            
            # Procesar Spring Isolator
            if quote_data[106] != "Seleccione una opción":  # Item_AddAccesory_Spring
                spring_data = get_spring_isolator_data(
                    quote_data[106],  # Item_AddAccesory_Spring
                    qty_genset,
                    Discount
                )
                if spring_data:
                    update_spring_isolator_pricing(quote_id, spring_data)
            
            # Definir todas las opciones con sus índices
            options = [
                ('band_heater', 108, 109),        # (tipo, item_index, desc_index)
                ('pmg_update', 110, 111),
                ('digital_regulator', 112, 113),
                ('voltage_rheostat', 114, 115),
                ('thermal_wrap', 116, 117),
                ('base_heater', 118, 119),
                ('battery_switch', 120, 121),
                ('battery_holder', 122, 123),
                ('oil_heater', 124, 125),
                ('oil_level_switch', 126, 127),
                ('common_alarm_relay', 128, 129),
                ('function_relay', 130, 131),
                ('coolant', 132, 133),
                ('oil', 134, 135),
                ('disconnect_switch', 136, 137),
                ('remote_estop', 138, 139)
            ]
            
            for option_type, item_idx, desc_idx in options:
                if quote_data[desc_idx] != "No":
                    option_data = get_accessory_option_data(
                        quote_data[item_idx],
                        qty_genset,
                        Discount
                    )
                    if option_data:
                        update_accessory_option_pricing(quote_id, option_type, option_data)
                        
            # ///// Seccion de Tanque /////
            # Procesar tanque principal
            tank_data = get_tank_data(
                kw_output,
                quote_data[140],  # Item_Tank_Autonomy
                quote_data[142],  # Item_Tank_type
                qty_genset,
                Discount
            )
            if tank_data:
                update_tank_pricing(quote_id, tank_data)
            
            # Procesar contenedor de derrames
            if quote_data[148] != "Seleccione una opción":  # Item_Tank_SpillCont
                spill_data = get_spill_containment_data(
                    quote_data[148],
                    qty_genset,
                    Discount
                )
                if spill_data:
                    update_tank_option_pricing(quote_id, 'spill_cont', spill_data)
            
            # Definir todas las opciones con sus índices
            options = [
                ('break_tray', 144, 145),        # (tipo, item_index, desc_index)
                ('fuel_level', 146, 147),
                ('overfill', 150, 151),
                ('dual_fuel', 152, 153),
                ('high_fuel', 154, 155),
                ('remote_alarm', 156, 157),
                ('vent_pipe', 158, 159),
                ('flammable', 160, 161),
                ('nfpa', 162, 163),
                ('no_smoking', 164, 165),
                ('tank_number', 166, 167),
                ('fluid_cont', 168, 169)
            ]
            
            for option_type, item_idx, desc_idx in options:
                if quote_data[desc_idx] != "No":
                    option_data = get_tank_option_data(
                        quote_data[item_idx],
                        qty_genset,
                        Discount
                    )
                    if option_data:
                        update_tank_option_pricing(quote_id, option_type, option_data)
            
            # ///// Seccion de Ultimos detalles /////
            # Procesar pruebas
            if quote_data[174] != "Seleccione una opción":  # Item_PrjWar_Testing
                testing_data = get_testing_data(
                    quote_data[174],  # Item_PrjWar_Testing
                    kw_output,
                    qty_genset,
                    Discount
                )
                if testing_data:
                    update_testing_pricing(quote_id, testing_data)
            
            #Volvemos a hacer la consulta a la tabla para obtener el precio untario caculado en este mismo proceso
            quote_data = get_quote_data(quote_id)
            
            # Procesar garantía
            if quote_data[170] != "Seleccione una opción":  # Item_PrjWar_Warranty
                warranty_data = get_warranty_data(
                    quote_data[170],  # Item_PrjWar_Warranty
                    qty_genset,
                    quote_data[176],
                    Discount
                )
                if warranty_data:
                    update_warranty_pricing(quote_id, warranty_data)

            return True
            
        except Exception as e:
            print(f"Error procesando precios: {e}")
            raise

    @app.route('/Ventas/VentasEUA/VEUcotizadorbase', methods=['GET', 'POST'])
    def cotizador_base():
        if request.method == 'POST':
            quote_id = request.form.get('quote_id')
            if not quote_id:
                # En lugar de redirigir, mostramos un error o volvemos a la página principal
                flash("No se proporcionó un ID de cotización válido", "error")
                return redirect(url_for('index'))  # Asumiendo que tienes una ruta 'index'
            session['quote_id'] = quote_id  # Guardamos el ID en sesión
            return redirect(url_for('cotizador_base'))  # Redirigir a GET con sesión        

        # Para GET, primero verificamos si hay un quote_id en la URL
        url_quote_id = request.args.get('quote_id')
        if url_quote_id:
            # Si hay un ID en la URL, sobrescribe el que está en la sesión
            session['quote_id'] = url_quote_id

        # Para GET, recuperamos la cotización usando el quote_id almacenado en sesión
        quote_id = session.get('quote_id')
        if not quote_id:
            # En lugar de redirigir a 'cotizador_eua', mostramos un error
            flash("No se encontró el ID de cotización en sesión", "error")
            return redirect(url_for('index'))  # Asumiendo que tienes una ruta 'index'

        # Obtener datos de la cotización, todo lo que incluye en el encabezado y datos generales
        General_Information = Get_General_Information(quote_id)
        
        #Construir la tabla de la plannta General
        CotizacionGenset_data = Get_CotizacionGenset_data(quote_id)
        table_CotizacionGenset = generate_quote_table_Genset(CotizacionGenset_data)
        price_CotizacionGenset = sum_total_prices(table_CotizacionGenset)
        
        #Construir la tabla de los Breakers
        CotizacionBreakers_data = Get_CotizacionBreakers_data(quote_id)
        table_CotizacionBreakers = generate_quote_table_breakers(CotizacionBreakers_data)
        price_CotizacionBreakers = sum_total_prices(table_CotizacionBreakers)
        
        #Construir la tabla del Control
        CotizacionControl_data = Get_CotizacionControl_data(quote_id)
        table_CotizacionControl = generate_quote_table_Control(CotizacionControl_data)
        price_CotizacionControl = sum_total_prices(table_CotizacionControl)
        
        #Construir la tabla de la caseta
        CotizacionEnclosure_data = Get_CotizacionEnclosure_data(quote_id)
        table_CotizacionEnclosure = generate_quote_table_Enclosure(CotizacionEnclosure_data)
        price_CotizacionEnclosure = sum_total_prices(table_CotizacionEnclosure)
        
        #Construir la tabla de los accesorios
        CotizacionAccesories_data = Get_CotizacionAccesories_data(quote_id)
        table_CotizacionAccesories = generate_quote_table_Accesories(CotizacionAccesories_data)
        price_CotizacionAccesories = sum_total_prices(table_CotizacionAccesories)
        
        #Construir la tabla del Tanque
        CotizacionTank_data = Get_CotizacionTank_data(quote_id)
        table_CotizacionTank = generate_quote_table_Tank(CotizacionTank_data)
        price_CotizacionTank = sum_total_prices(table_CotizacionTank)
        
        Genset_price = price_CotizacionGenset + price_CotizacionBreakers + price_CotizacionControl + price_CotizacionEnclosure + price_CotizacionAccesories + price_CotizacionTank
        
        #Construir la tabla de las pruebas
        CotizacionWarrantyAndTest_data = Get_warranty_and_testing_pricing(quote_id, Genset_price)  
        table_WarrantyAndTest = generate_quote_table_WT(CotizacionWarrantyAndTest_data)
        price_WarrantyAndTest = sum_total_prices(table_WarrantyAndTest)
        
        GranTotal = Genset_price + price_WarrantyAndTest

        # Función que retorna un diccionario con los datos de los descuentos por paises.
        countryDiscountData = get_country_discont(quote_id, GranTotal)

        #Variable que suma el total original + el total condescuentos calculados
        ofertaComercial = Decimal(str(GranTotal)) + countryDiscountData['total']

        # Se actualiza la tabla CZE_Cuotes con el total y con la oferta comercial
        update_commercial_country_values(quote_id, countryDiscountData['total'], ofertaComercial)        

        emails_Quotes_NrtAme = {"alexis.moreno@igsa.com.mx", "carlos.velazquezm@igsa.com.mx"}
        #Validar si hay un registro guardado en la tabla CZE_Quotes si hay datos en RoutePDF
        
        context = {
            'data': General_Information, 
            'table_CotizacionGenset' : table_CotizacionGenset,
            'table_CotizacionBreakers': table_CotizacionBreakers,
            'table_CotizacionControl': table_CotizacionControl,
            'table_CotizacionEnclosure': table_CotizacionEnclosure,
            'table_CotizacionAccesories': table_CotizacionAccesories,
            'table_CotizacionTank': table_CotizacionTank,
            'table_WarrantyAndTest': table_WarrantyAndTest,
            'price_CotizacionGenset': price_CotizacionGenset,
            'price_CotizacionBreakers': price_CotizacionBreakers,
            'price_CotizacionControl': price_CotizacionControl,
            'price_CotizacionEnclosure': price_CotizacionEnclosure,
            'price_CotizacionAccesories': price_CotizacionAccesories,
            'price_CotizacionTank': price_CotizacionTank,
            'price_WarrantyAndTest': price_WarrantyAndTest,
            'GranTotal': GranTotal,
            'countryData': countryDiscountData, # Contiene los datos de descuentos.
            'ofertaComercial': ofertaComercial, 
            'today_date': datetime.now().strftime('%d/%m/%Y'),
            'emails_Quotes_NrtAme' : emails_Quotes_NrtAme,
            'show_send_button': True,  # Para mostrar el botón de enviar
            'quote_id': quote_id  # Asegúrate de que quote_id esté disponible en el contexto
        }
        
        return render_template('Ventas/VentasEUA/VEUcotizadorbase.html', **context)    

    def Get_General_Information(quote_id):
        
        # Obtener datos de la cotización
        quote_data = get_Definitive_quote_data(quote_id)
        if not quote_data:
            return "Error: No se encontraron datos para la cotización", 404
        
        quote_data = {k: convert_decimal(v) for k, v in quote_data.items()}
        
        DATE = datetime.now().strftime("%Y-%m-%d")

        # Consultas adicionales para obtener información completa de la planta
        Genset_CostID = quote_data['Genset_CostID']
        Genset_model = get_genset_model(Genset_CostID)
        
        VoltageID = quote_data['VoltageID']
        Datos_voltajes = get_frecuency(VoltageID)
        
        # Construcción de variable tipo diccionario anidado con la informacion general de la cotización
        General_Information = {
                "quote_id": quote_id,
                "project_info": {
                    "project": quote_data['Project'],
                    "customer_requirements": quote_data['ReqCustomer']
                },
                "date": {
                    "DATE": DATE,
                },
                "general_info": {
                    
                    "Genset_model": Genset_model,
                    "FuelTypeFront": quote_data['FuelTypeFront'],
                    "KWOutput": f"{quote_data['KWOutput']} KW", 
                    "Frecuency": f"{Datos_voltajes['Frecuency']} Hz",
                    "VoltageID": f"{quote_data['VoltageID']} V",
                    "Phases": Datos_voltajes["Phases"],
                    "Certification": quote_data['Certification'],
                },
                "engine": {
                    "EngineBrand": quote_data['EngineBrand'],
                    "EngineModel": quote_data['EngineModel'],
                    "specifications": {
                        "Engine_Tier": quote_data['Engine_Tier'],
                        "Engine_Rpm": quote_data['Engine_Rpm'],
                        "Engine_Power": quote_data['Engine_Power'],
                        "Engine_NumberOfCylinder": quote_data['Engine_NumberOfCylinder'],
                        "Engine_Aspiration": quote_data['Engine_Aspiration'],
                        "Engine_Governor_type": quote_data['Engine_Governor_type'],
                        "Engine_Control_voltage": quote_data['Engine_Control_voltage'],
                        "Engine_RadiatorTemp": quote_data['Engine_RadiatorTemp']
                    },
                    "Engine_TSheet": quote_data['Engine_TSheet']
                },
                "alternator": {
                    "AlternatorBrand": quote_data['AlternatorBrand'],
                    "AlternatorModel": quote_data['AlternatorModel'],
                    "specifications": {
                        "Altern_Powerfactor": quote_data['Altern_Powerfactor'],
                        "Altern_Insulation_Sys": quote_data['Altern_Insulation_Sys'],
                        "Altern_Control_System": quote_data['Altern_Control_System'],
                        "Altern_Protection": quote_data['Altern_Protection'],
                        "Altern_AvrModel": quote_data['Altern_AvrModel'],
                        "Altern_VoltageRegulat": quote_data['Altern_VoltageRegulat'],
                        "Altern_Class_temp_rise": quote_data['Altern_Class_temp_rise']
                    },
                    "Altern_TSheet": quote_data['Altern_TSheet']
                },
                "Breakers": {
                    "Breaker1": {
                        "Breaker1": quote_data['Breaker1']
                    },
                    "Breaker2": {
                        "Breaker2": quote_data['Breaker2']
                    },
                    "Breaker3": {
                        "Breaker3": quote_data['Breaker3']
                    }
                },
                "controller": {
                    "ControlModel": quote_data['ControlModel'],
                    "AdicionalyConfigController": {
                        "BateryCharger": quote_data['BateryCharger']
                    }
                },
                "Tank": {
                    "BaseTank": quote_data['BaseTank'],
                    "TankAutonomy": quote_data['TankAutonomy']
                },
                "Enclosure": {
                    "AcousticEnclosure": quote_data['AcousticEnclosure']
                },              
                "Customer": {
                    "CustomerCompany": quote_data['CustomerCompany'],
                    "CustomerAddress": quote_data['CustomerAddress'],
                    "CustomerContact": quote_data['CustomerContact'],
                    "CustomerEmail": quote_data['CustomerEmail'],
                    "CustomerTel": quote_data['CustomerTel']
                },
                "Seller": {
                    "SellerName": quote_data['SellerName'],
                    "SellerEmail": quote_data['SellerEmail'],
                    "SellerPhone": quote_data['SellerPhone']
                }
            }
        
        return General_Information
    
    def Get_CotizacionGenset_data(quote_id):
        
        # Obtener datos de la cotización
        quote_data = get_Definitive_quote_data(quote_id)
        if not quote_data:
            return "Error: No se encontraron datos para la cotización", 404
        
        quote_data = {k: convert_decimal(v) for k, v in quote_data.items()}
        
        DATE = datetime.now().strftime("%Y-%m-%d")

        #------------------------CONSULTAS ADICIONALES-------------------------
        Genset_CostID = quote_data['Genset_CostID']
        Genset_model = get_genset_model(Genset_CostID)
        
        VoltageID = quote_data['VoltageID']
        Datos_voltajes = get_frecuency(VoltageID)
        
        GensetDESC = (
            f"{quote_data.get('FuelTypeFront', '')} GENERATOR SET MODEL {Genset_model}, "
            f"STANDBY POWER {quote_data.get('KWOutput', '')}, {quote_data.get('Voltage_Front', '')}. "
            f"{quote_data.get('EngineBrand', '')} ENGINE {quote_data.get('EngineModel', '')}, "
            f"{quote_data.get('AlternatorBrand', '')} ALTERNATOR {quote_data.get('AlternatorModel', '')}, "
            "STANDARD ACCESSORIES"
        )
        GensetQTYTOT = quote_data['QtyGenset']
        
        CotizacionGenset_data = {
                "quote_id": quote_id,
                "Genset": {
                    "Genset_model": Genset_model, # ----------------------------Item del Genset
                    "GensetDESC": GensetDESC, # ----------------------------Descripción del Genset
                    "GensetQTYTOT": GensetQTYTOT, # ----------------------------Cantidad de Genset
                    "Genset_Unit_Price": quote_data['Genset_Unit_Price'], # ----------------------------Precio unitario de Genset
                    "Genset_TSheet": quote_data['Genset_TSheet'], # ---------------------------- Ficha técnica de Genset
                    "Genset_PriceTot": quote_data['Genset_PriceTot'] # ----------------------------Precio total de Genset
                }
            }

        return CotizacionGenset_data
    def generate_quote_table_Genset(CotizacionGenset_data):
        """
        Genera el HTML para la tabla del generador (Genset) con enlaces a fichas técnicas
    
        Args:
            CotizacionGenset_data (dict): Datos del generador
        
        Returns:
            str: HTML para la tabla del generador
        """
        html = """
        <tbody>
        """
    
        # Función para renderizar una fila de la tabla con enlace a la ficha técnica
        def render_row(item, description, qty, unit_price, total_price, tech_sheet=None):
            if description is None or description == "":
                return ""
        
            # Formatear precios
            formatted_unit_price = format_price(unit_price)
            formatted_total_price = format_price(total_price)
        
            # Si hay ficha técnica, crear un enlace, de lo contrario mostrar solo el texto
            if tech_sheet and tech_sheet.strip():
                item_cell = f'<a href="{tech_sheet}" target="_blank" class="tech-sheet-link">{item or ""}</a>'
            else:
                item_cell = item or ""
        
            return f"""
            <tr>
                <td>{item_cell}</td>
                <td>{description or ""}</td>
                <td>{qty or ""}</td>
                <td>{formatted_unit_price}</td>
                <td>{formatted_total_price}</td>
            </tr>
            """
    
        # Obtener datos del generador
        genset = CotizacionGenset_data.get("Genset", {})
        
        # Generar fila para el generador principal
        if genset and genset.get("GensetDESC"):
            html += render_row(
                genset.get("Genset_model"),
                genset.get("GensetDESC"),
                genset.get("GensetQTYTOT"),
                genset.get("Genset_Unit_Price"),
                genset.get("Genset_PriceTot"),
                genset.get("Genset_TSheet")
            )
        
        html += """
        </tbody>
        """
        
        return html
    
    def Get_CotizacionBreakers_data(quote_id):
        
        # Obtener datos de la cotización
        quote_data = get_Definitive_quote_data(quote_id)
        if not quote_data:
            return "Error: No se encontraron datos para la cotización", 404
        
        quote_data = {k: convert_decimal(v) for k, v in quote_data.items()}
        
        #------------------------DESCRIPTION BREAKER1-------------------------
        #Select con la descripción cargada dentro del mismo select
        Breaker1QTYTOT = quote_data['QtyGenset']
        #Select del tipo SI/NO
        Shunt_trip1DESC = 'Shunt trip'
        Shunt_trip1_QTYTOT = quote_data['QtyGenset']
        #Select del tipo SI/NO
        Shunt_trip_wiring1DESC = 'Shunt trip wiring'
        Shunt_trip_wiring1_QTYTOT = quote_data['QtyGenset']
        #Select del tipo SI/NO
        Item_GFI1DESC = 'GFI (Ground fault indication)'
        Item_GFI1_QTYTOT = quote_data['QtyGenset']
        #Select con la descripción cargada dentro del mismo select
        Protection_type1_QTYTOT = quote_data['QtyGenset']
        #Select del tipo SI/NO
        Auxiliary_contactsDESC = 'Auxiliary contacts'
        Auxiliary_contacts_QTYTOT = quote_data['QtyGenset']
        #Select del tipo SI/NO
        Breaker_LockDESC = 'Item_Breaker_L1'
        Breaker_Lock_QTYTOT = quote_data['QtyGenset']
        #Select del tipo SI/NO
        Motorized_BreakerDESC = 'Motorized Breaker'
        Motorized_Breaker_QTYTOT = quote_data['QtyGenset']
        #------------------------DESCRIPTION BREAKER2-------------------------
        Breaker2QTYTOT = quote_data['QtyGenset']

        Shunt_trip2DESC = 'Shunt trip'
        Shunt_trip2_QTYTOT = quote_data['QtyGenset']

        Shunt_trip_wiring2DESC = 'Shunt trip wiring'
        Shunt_trip_wiring2_QTYTOT = quote_data['QtyGenset']

        Item_GFI2DESC = 'GFI (Ground fault indication)'
        Item_GFI2_QTYTOT = quote_data['QtyGenset']

        Protection_type2_QTYTOT = quote_data['QtyGenset']

        Auxiliary_contacts2DESC = 'Auxiliary contacts'
        Auxiliary_contacts2_QTYTOT = quote_data['QtyGenset']

        Breaker_Lock2DESC = 'Item_Breaker_L1'
        Breaker_Lock2_QTYTOT = quote_data['QtyGenset']

        Motorized_Breaker2DESC = 'Motorized Breaker'
        Motorized_Breaker2_QTYTOT = quote_data['QtyGenset']

        #------------------------DESCRIPTION BREAKER3-------------------------
        Breaker3QTYTOT = quote_data['QtyGenset']

        Shunt_trip3DESC = 'Shunt trip'
        Shunt_trip3_QTYTOT = quote_data['QtyGenset']

        Shunt_trip_wiring3DESC = 'Shunt trip wiring'
        Shunt_trip_wiring3_QTYTOT = quote_data['QtyGenset']

        Item_GFI3DESC = 'GFI (Ground fault indication)'
        Item_GFI3_QTYTOT = quote_data['QtyGenset']

        Protection_type3_QTYTOT = quote_data['QtyGenset']

        Auxiliary_contacts3DESC = 'Auxiliary contacts'
        Auxiliary_contacts3_QTYTOT = quote_data['QtyGenset']

        Breaker_Lock3DESC = 'Item_Breaker_L1'
        Breaker_Lock3_QTYTOT = quote_data['QtyGenset']

        Motorized_Breaker3DESC = 'Motorized Breaker'
        Motorized_Breaker3_QTYTOT = quote_data['QtyGenset']        
        
        CotizacionBreakers_data = {
                "quote_id": quote_id,
                "Breakers": {
                    "Breaker1": {
                        # Se coloca si Item_breaker1 es diferente de Seleccione una opcion o Select an option
                        "Item_breaker1": quote_data['Item_breaker1'], # ----------------------------Item Breaker1
                        "Breaker1": quote_data['Breaker1'], # ----------------------------Descripción del Breaker1
                        "Breaker1QTYTOT": Breaker1QTYTOT,# ----------------------------Cantidad de Breaker1
                        "Breaker1_Price": quote_data['Breaker1_Price'],# ----------------------------Precio unitario de Breaker1
                        "Breaker1_TSheet": quote_data['Breaker1_TSheet'],# ---------------------------- Ficha técnica de Breaker1
                        "Breaker1_PriceTot": quote_data['Breaker1_PriceTot'],# ----------------------------Precio total de Breaker1
                        "ConfigAndAccesories_Breaker1":{
                            
                            # Shunt_trip1. Se coloca si Shunt_trip1 es diferente a No
                            "Item_Sunt_t1": quote_data['Item_Sunt_t1'], # ----------------------------Item del Shunt trip1
                            "Shunt_trip1": quote_data['Shunt_trip1'], #
                            "Shunt_trip1DESC": Shunt_trip1DESC, # ----------------------------Descripción del Shunt trip1
                            "Shunt_trip1_QTYTOT": Shunt_trip1_QTYTOT, # ----------------------------Cantidad total del Shunt trip1
                            "Sunt_t1_Price": quote_data['Sunt_t1_Price'], # ----------------------------Precio unitario del Shunt trip1
                            "Sunt_t1_TSheet": quote_data['Sunt_t1_TSheet'], # ----------------------------Ficha técnica del Shunt trip1
                            "Sunt_t1_PriceTot": quote_data['Sunt_t1_PriceTot'], # ----------------------------Precio total del Shunt trip1
                            
                            # Shunt_trip_wiring1. Se coloca si Shunt_trip_wiring1 es diferente a No
                            "Item_Sunt_w1": quote_data['Item_Sunt_w1'], # ----------------------------Item del cableado del Shunt trip1
                            "Shunt_trip_wiring1": quote_data['Shunt_trip_wiring1'],
                            "Shunt_trip_wiring1DESC": Shunt_trip_wiring1DESC, # ----------------------------Descripción del cableado del Shunt trip1
                            "Shunt_trip_wiring1_QTYTOT": Shunt_trip_wiring1_QTYTOT, # ----------------------------Cantidad total del cableado del Shunt trip1
                            "Sunt_w1_Price": quote_data['Sunt_w1_Price'], # ----------------------------Precio unitario del cableado del Shunt trip1
                            "Sunt_w1_TSheet": quote_data['Sunt_w1_TSheet'], # ----------------------------Ficha técnica del cableado del Shunt trip1
                            "Sunt_w1_PriceTot": quote_data['Sunt_w1_PriceTot'], # ----------------------------Precio total del cableado del Shunt trip1
                            
                            # GFI1. Se coloca si GFI1 es diferente a No
                            "Item_GFI1": quote_data['Item_GFI1'], # ----------------------------Item del GFI1
                            "GFI1": quote_data['GFI1'],
                            "Item_GFI1DESC": Item_GFI1DESC, # ----------------------------Descripción del GFI1
                            "Item_GFI1_QTYTOT": Item_GFI1_QTYTOT, # ----------------------------Cantidad total del GFI1
                            "GFI1_Price": quote_data['GFI1_Price'], # ----------------------------Precio unitario del GFI1
                            "GFI1_TSheet": quote_data['GFI1_TSheet'], # ----------------------------Ficha técnica del GFI1
                            "GFI1_PriceTot": quote_data['GFI1_PriceTot'], # ----------------------------Precio total del GFI1
                            
                            # Protection_type1. Se coloca si Protection_type1 es diferente de Seleccione una opcion o Select an option o Seleccione un modelo de interrptor o Select a breaker model
                            "Item_Proyection_t1": quote_data['Item_Proyection_t1'], # ----------------------------Item del tipo de protección 1
                            "Protection_type1": quote_data['Protection_type1'], # ----------------------------Descripción del tipo de protección 1
                            "Protection_type1_QTYTOT": Protection_type1_QTYTOT, # ----------------------------Cantidad total del tipo de protección 1
                            "Proyection_t1_Price": quote_data['Proyection_t1_Price'], # ----------------------------Precio unitario del tipo de protección 1
                            "Proyection_t1_TSheet": quote_data['Proyection_t1_TSheet'], # ----------------------------Ficha técnica del tipo de protección 1
                            "Proyection_t1_PriceTot": quote_data['Proyection_t1_PriceTot'], # ----------------------------Precio total del tipo de protección 1
                            
                            # Auxiliary_contacts1.  Se coloca si Auxiliary_contacts1 es diferente a No
                            "Item_Auxiliary_c1": quote_data['Item_Auxiliary_c1'], # ----------------------------Item de contactos auxiliares 1
                            "Auxiliary_contacts1": quote_data['Auxiliary_contacts1'],
                            "Auxiliary_contactsDESC": Auxiliary_contactsDESC, # ----------------------------Descripción de contactos auxiliares 1
                            "Auxiliary_contacts_QTYTOT": Auxiliary_contacts_QTYTOT, # ----------------------------Cantidad total de contactos auxiliares 1
                            "Auxiliary_c1_Price": quote_data['Auxiliary_c1_Price'], # ----------------------------Precio unitario de contactos auxiliares 1
                            "Auxiliary_c1_TSheet": quote_data['Auxiliary_c1_TSheet'], # ----------------------------Ficha técnica de contactos auxiliares 1
                            "Auxiliary_c1_PriceTot": quote_data['Auxiliary_c1_PriceTot'], # ----------------------------Precio total de contactos auxiliares 1
                            
                            # Breaker_Lock1. Se coloca si Breaker_Lock1 es diferente a No
                            "Item_Breaker_L1": quote_data['Item_Breaker_L1'], # ----------------------------Item del bloqueo de Breaker 1
                            "Breaker_Lock1": quote_data['Breaker_Lock1'],
                            "Breaker_LockDESC": Breaker_LockDESC, # ----------------------------Descripción del bloqueo de Breaker 1
                            "Breaker_Lock_QTYTOT": Breaker_Lock_QTYTOT, # ----------------------------Cantidad total del bloqueo de Breaker 1
                            "Breaker_L1_Price": quote_data['Breaker_L1_Price'], # ----------------------------Precio unitario del bloqueo de Breaker 1
                            "Breaker_L1_TSheet": quote_data['Breaker_L1_TSheet'], # ----------------------------Ficha técnica del bloqueo de Breaker 1
                            "Breaker_L1_PriceTot": quote_data['Breaker_L1_PriceTot'], # ----------------------------Precio total del bloqueo de Breaker 1
                            
                            # Motorized_Breaker1. Se coloca si Motorized_Breaker1 es diferente a No
                            "Item_Motorized_B1": quote_data['Item_Motorized_B1'], # ----------------------------Item del Breaker motorizado 1
                            "Motorized_Breaker1": quote_data['Motorized_Breaker1'],
                            "Motorized_BreakerDESC": Motorized_BreakerDESC, # ----------------------------Descripción del Breaker motorizado 1
                            "Motorized_Breaker_QTYTOT": Motorized_Breaker_QTYTOT, # ----------------------------Cantidad total del Breaker motorizado 1
                            "Motorized_B1_Price": quote_data['Motorized_B1_Price'], # ----------------------------Precio unitario del Breaker motorizado 1
                            "Motorized_B1_TSheet": quote_data['Motorized_B1_TSheet'], # ----------------------------Ficha técnica del Breaker motorizado 1
                            "Motorized_B1_PriceTot": quote_data['Motorized_B1_PriceTot'], # ----------------------------Precio total del Breaker motorizado 1
                        }
                    },
                    "Breaker2": {
                        # Se coloca si Item_breaker2 es diferente de Seleccione una opcion o Select an option
                        "Item_breaker2": quote_data['Item_breaker2'],# ----------------------------Item Breaker2
                        "Breaker2": quote_data['Breaker2'],# ----------------------------Descripción del Breaker2
                        "Breaker2QTYTOT": Breaker2QTYTOT,# ----------------------------Cantidad de Breaker2
                        "Breaker2_Price": quote_data['Breaker2_Price'],# ----------------------------Precio unitario de Breaker2
                        "Breaker2_TSheet": quote_data['Breaker2_TSheet'],# ---------------------------- Ficha técnica de Breaker2
                        "Breaker2_PriceTot": quote_data['Breaker2_PriceTot'],# ----------------------------Precio total de Breaker2
                        "ConfigAndAccesories_Breaker2":{
                            
                            # Shunt_trip2. Se coloca si Shunt_trip2 es diferente a No
                            "Item_Sunt_t2": quote_data['Item_Sunt_t2'],# ----------------------------Item del Shunt trip2
                            "Shunt_trip2": quote_data['Shunt_trip2'],
                            "Shunt_trip2DESC": Shunt_trip2DESC,# ----------------------------Descripción del Shunt trip2
                            "Shunt_trip2_QTYTOT": Shunt_trip2_QTYTOT,# ----------------------------Cantidad total del Shunt trip2
                            "Sunt_t2_Price": quote_data['Sunt_t2_Price'],# ----------------------------Precio unitario del Shunt trip2
                            "Sunt_t2_TSheet": quote_data['Sunt_t2_TSheet'],# ----------------------------Ficha técnica del Shunt trip2
                            "Sunt_t2_PriceTot": quote_data['Sunt_t2_PriceTot'],# ----------------------------Precio total del Shunt trip2
                            
                            # Shunt_trip_wiring2. Se coloca si Shunt_trip_wiring2 es diferente a No
                            "Item_Sunt_w2": quote_data['Item_Sunt_w2'],#
                            "Shunt_trip_wiring2": quote_data['Shunt_trip_wiring2'],
                            "Shunt_trip_wiring2DESC": Shunt_trip_wiring2DESC,# ----------------------------Descripción del cableado del Shunt trip2
                            "Shunt_trip_wiring2_QTYTOT": Shunt_trip_wiring2_QTYTOT,# ----------------------------Cantidad total del cableado del Shunt trip2
                            "Sunt_w2_Price": quote_data['Sunt_w2_Price'],# ----------------------------Precio unitario del cableado del Shunt trip2
                            "Sunt_w2_TSheet": quote_data['Sunt_w2_TSheet'],# ----------------------------Ficha técnica del cableado del Shunt trip2
                            "Sunt_w2_PriceTot": quote_data['Sunt_w2_PriceTot'],# ----------------------------Precio total del cableado del Shunt trip2
                            
                            # GFI2. Se coloca si GFI2 es diferente a No
                            "Item_GFI2": quote_data['Item_GFI2'],# ----------------------------Item del GFI2
                            "GFI2": quote_data['GFI2'],
                            "Item_GFI2DESC": Item_GFI2DESC,# ----------------------------Descripción del GFI2
                            "Item_GFI2_QTYTOT": Item_GFI2_QTYTOT,# ----------------------------Cantidad total del GFI2
                            "GFI2_Price": quote_data['GFI2_Price'],# ----------------------------Precio unitario del GFI2
                            "GFI2_TSheet": quote_data['GFI2_TSheet'],# ----------------------------Ficha técnica del GFI2
                            "GFI2_PriceTot": quote_data['GFI2_PriceTot'],# ----------------------------Precio total del GFI2
                            
                            # Protection_type2. Se coloca si Protection_type2 es diferente de Seleccione una opcion o Select an option o Seleccione un modelo de interrptor o Select a breaker model
                            "Item_Proyection_t2": quote_data['Item_Proyection_t2'],# ----------------------------Item del tipo de protección 2
                            "Protection_type2": quote_data['Protection_type2'],# ----------------------------Descripción del tipo de protección 2
                            "Protection_type2_QTYTOT":Protection_type2_QTYTOT,# ----------------------------Cantidad total del tipo de protección 2
                            "Proyection_t2_Price": quote_data['Proyection_t2_Price'],# ----------------------------Precio unitario del tipo de protección 2
                            "Proyection_t2_TSheet": quote_data['Proyection_t2_TSheet'],# ----------------------------Ficha técnica del tipo de protección 2
                            "Proyection_t2_PriceTot": quote_data['Proyection_t2_PriceTot'],# ----------------------------Precio total del tipo de protección 2
                            
                            # Auxiliary_contacts2. Se coloca si Auxiliary_contacts2 es diferente a No
                            "Item_Auxiliary_c2": quote_data['Item_Auxiliary_c2'],# ----------------------------Item de contactos auxiliares 2
                            "Auxiliary_contacts2": quote_data['Auxiliary_contacts2'],
                            "Auxiliary_contacts2DESC": Auxiliary_contacts2DESC,# ----------------------------Descripción de contactos auxiliares 2
                            "Auxiliary_contacts2_QTYTOT": Auxiliary_contacts2_QTYTOT,# ----------------------------Cantidad total de contactos auxiliares 2
                            "Auxiliary_c2_Price": quote_data['Auxiliary_c2_Price'],# ----------------------------Precio unitario de contactos auxiliares 2
                            "Auxiliary_c2_TSheet": quote_data['Auxiliary_c2_TSheet'],# ----------------------------Ficha técnica de contactos auxiliares 2
                            "Auxiliary_c2_PriceTot": quote_data['Auxiliary_c2_PriceTot'],# ----------------------------Precio total de contactos auxiliares 2
                            
                            # Breaker_Lock2. Se coloca si Breaker_Lock2 es diferente a No
                            "Item_Breaker_L2": quote_data['Item_Breaker_L2'],# ----------------------------Item del bloqueo de Breaker 2
                            "Breaker_Lock2": quote_data['Breaker_Lock2'],
                            "Breaker_Lock2DESC": Breaker_Lock2DESC,# ----------------------------Descripción del bloqueo de Breaker 2
                            "Breaker_Lock2_QTYTOT": Breaker_Lock2_QTYTOT,# ----------------------------Cantidad total del bloqueo de Breaker 2
                            "Breaker_L2_Price": quote_data['Breaker_L2_Price'],# ----------------------------Precio unitario del bloqueo de Breaker 2
                            "Breaker_L2_TSheet": quote_data['Breaker_L2_TSheet'],# ----------------------------Ficha técnica del bloqueo de Breaker 2
                            "Breaker_L2_PriceTot": quote_data['Breaker_L2_PriceTot'],# ----------------------------Precio total del bloqueo de Breaker 2
                            
                            # Motorized_Breaker2. Se coloca si Motorized_Breaker2 es diferente a No
                            "Item_Motorized_B2": quote_data['Item_Motorized_B2'],# ----------------------------Item del Breaker motorizado 2
                            "Motorized_Breaker2": quote_data['Motorized_Breaker2'],
                            "Motorized_Breaker2DESC": Motorized_Breaker2DESC,# ----------------------------Descripción del Breaker motorizado 2
                            "Motorized_Breaker2_QTYTOT": Motorized_Breaker2_QTYTOT,# ----------------------------Cantidad total del Breaker motorizado 2
                            "Motorized_B2_Price": quote_data['Motorized_B2_Price'],# ----------------------------Precio unitario del Breaker motorizado 2
                            "Motorized_B2_TSheet": quote_data['Motorized_B2_TSheet'],# ----------------------------Ficha técnica del Breaker motorizado 2
                            "Motorized_B2_PriceTot": quote_data['Motorized_B2_PriceTot'],# ----------------------------Precio total del Breaker motorizado 2
                        }
                    },
                    "Breaker3": {
                        # Se coloca si Item_breaker3 es diferente de Seleccione una opcion o Select an option
                        "Item_breaker3": quote_data['Item_breaker3'],# ----------------------------Item Breaker3
                        "Breaker3": quote_data['Breaker3'],# ----------------------------Descripción del Breaker3
                        "Breaker3QTYTOT": Breaker3QTYTOT,# ----------------------------Cantidad de Breaker3
                        "Breaker3_Price": quote_data['Breaker3_Price'],# ----------------------------Precio unitario de Breaker3
                        "Breaker3_TSheet": quote_data['Breaker3_TSheet'],# ---------------------------- Ficha técnica de Breaker3
                        "Breaker3_PriceTot": quote_data['Breaker3_PriceTot'],# ----------------------------Precio total de Breaker3
                        "ConfigAndAccesories_Breaker3":{
                            
                            # Shunt_trip3. Se coloca si Shunt_trip3 es diferente a No
                            "Item_Sunt_t3": quote_data['Item_Sunt_t3'],# ----------------------------Item del Shunt trip3
                            "Shunt_trip3": quote_data['Shunt_trip3'],
                            "Shunt_trip3DESC": Shunt_trip3DESC,# ----------------------------Descripción del Shunt trip3
                            "Shunt_trip3_QTYTOT": Shunt_trip3_QTYTOT,# ----------------------------Cantidad total del Shunt trip3
                            "Sunt_t3_Price": quote_data['Sunt_t3_Price'],# ----------------------------Precio unitario del Shunt trip3
                            "Sunt_t3_TSheet": quote_data['Sunt_t3_TSheet'],# ----------------------------Ficha técnica del Shunt trip3
                            "Sunt_t3_PriceTot": quote_data['Sunt_t3_PriceTot'],# ----------------------------Precio total del Shunt trip3
                            
                            # Shunt_trip_wiring3. Se coloca si Shunt_trip_wiring3 es diferente a No
                            "Item_Sunt_w3": quote_data['Item_Sunt_w3'],# ----------------------------Item del cableado del Shunt trip3
                            "Shunt_trip_wiring3": quote_data['Shunt_trip_wiring3'],
                            "Shunt_trip_wiring3DESC": Shunt_trip_wiring3DESC,# ----------------------------Descripción del cableado del Shunt trip3
                            "Shunt_trip_wiring3_QTYTOT": Shunt_trip_wiring3_QTYTOT,# ----------------------------Cantidad total del cableado del Shunt trip3
                            "Sunt_w3_Price": quote_data['Sunt_w3_Price'],# ----------------------------Precio unitario del cableado del Shunt trip3
                            "Sunt_w3_TSheet": quote_data['Sunt_w3_TSheet'],# ----------------------------Ficha técnica del cableado del Shunt trip3
                            "Sunt_w3_PriceTot": quote_data['Sunt_w3_PriceTot'],# ----------------------------Precio total del cableado del Shunt trip3
                            
                            # GFI3. Se coloca si GFI3 es diferente a No
                            "Item_GFI3": quote_data['Item_GFI3'],# ----------------------------Item del GFI3
                            "GFI3": quote_data['GFI3'],
                            "Item_GFI3DESC": Item_GFI3DESC,# ----------------------------Descripción del GFI3
                            "Item_GFI3_QTYTOT": Item_GFI3_QTYTOT,# ----------------------------Cantidad total del GFI3
                            "GFI3_Price": quote_data['GFI3_Price'],# ----------------------------Precio unitario del GFI3
                            "GFI3_TSheet": quote_data['GFI3_TSheet'],# ----------------------------Ficha técnica del GFI3
                            "GFI3_PriceTot": quote_data['GFI3_PriceTot'],# ----------------------------Precio total del GFI3
                            
                            # Protection_type3. Se coloca si Protection_type3 es diferente de Seleccione una opcion o Select an option o Seleccione un modelo de interrptor o Select a breaker model
                            "Item_Proyection_t3": quote_data['Item_Proyection_t3'],# ----------------------------Item del tipo de protección 3
                            "Protection_type3": quote_data['Protection_type3'],# ----------------------------Descripción del tipo de protección 3
                            "Protection_type3_QTYTOT": Protection_type3_QTYTOT,# ----------------------------Cantidad total del tipo de protección 3
                            "Proyection_t3_Price": quote_data['Proyection_t3_Price'],# ----------------------------Precio unitario del tipo de protección 3
                            "Proyection_t3_TSheet": quote_data['Proyection_t3_TSheet'],# ----------------------------Ficha técnica del tipo de protección 3
                            "Proyection_t3_PriceTot": quote_data['Proyection_t3_PriceTot'],# ----------------------------Precio total del tipo de protección 3
                            
                            # Auxiliary_contacts3. Se coloca si Auxiliary_contacts3 es diferente a No
                            "Item_Auxiliary_c3": quote_data['Item_Auxiliary_c3'],# ----------------------------Item de contactos auxiliares 3
                            "Auxiliary_contacts3": quote_data['Auxiliary_contacts3'],
                            "Auxiliary_contacts3DESC": Auxiliary_contacts3DESC,# ----------------------------Descripción de contactos auxiliares 3
                            "Auxiliary_contacts3_QTYTOT": Auxiliary_contacts3_QTYTOT,# ----------------------------Cantidad total de contactos auxiliares 3
                            "Auxiliary_c3_Price": quote_data['Auxiliary_c3_Price'],# ----------------------------Precio unitario de contactos auxiliares 3
                            "Auxiliary_c3_TSheet": quote_data['Auxiliary_c3_TSheet'],# ----------------------------Ficha técnica de contactos auxiliares 3
                            "Auxiliary_c3_PriceTot": quote_data['Auxiliary_c3_PriceTot'],# ----------------------------Precio total de contactos auxiliares 3
                            
                            # Breaker_Lock3. Se coloca si Breaker_Lock3 es diferente a No
                            "Item_Breaker_L3": quote_data['Item_Breaker_L3'],# ----------------------------Item del bloqueo de Breaker 3
                            "Breaker_Lock3": quote_data['Breaker_Lock3'],
                            "Breaker_Lock3DESC":Breaker_Lock3DESC,# ----------------------------Descripción del bloqueo de Breaker 3
                            "Breaker_Lock3_QTYTOT": Breaker_Lock3_QTYTOT,# ----------------------------Cantidad total del bloqueo de Breaker 3
                            "Breaker_L3_Price": quote_data['Breaker_L3_Price'],# ----------------------------Precio unitario del bloqueo de Breaker 3
                            "Breaker_L3_TSheet": quote_data['Breaker_L3_TSheet'],# ----------------------------Ficha técnica del bloqueo de Breaker 3
                            "Breaker_L3_PriceTot": quote_data['Breaker_L3_PriceTot'],# ----------------------------Precio total del bloqueo de Breaker 3
                            
                            # Motorized_Breaker3. Se coloca si Motorized_Breaker3 es diferente a No
                            "Item_Motorized_B3": quote_data['Item_Motorized_B3'],# ----------------------------Item del Breaker motorizado 3
                            "Motorized_Breaker3": quote_data['Motorized_Breaker3'],
                            "Motorized_Breaker3DESC":Motorized_Breaker3DESC,# ----------------------------Descripción del Breaker motorizado 3
                            "Motorized_Breaker3_QTYTOT": Motorized_Breaker3_QTYTOT,# ----------------------------Cantidad total del Breaker motorizado 3
                            "Motorized_B3_Price": quote_data['Motorized_B3_Price'],# ----------------------------Precio unitario del Breaker motorizado 3
                            "Motorized_B3_TSheet": quote_data['Motorized_B3_TSheet'],# ----------------------------Ficha técnica del Breaker motorizado 3
                            "Motorized_B3_PriceTot": quote_data['Motorized_B3_PriceTot']# ----------------------------Precio total del Breaker motorizado 3
                        }
                    }
                }
        }
        
        return CotizacionBreakers_data
    def generate_quote_table_breakers(CotizacionBreakers_data):
        """
        Genera el HTML para la tabla de breakers con enlaces a fichas técnicas
    
        Args:
            CotizacionBreakers_data (dict): Datos de los breakers
        
        Returns:
            str: HTML para la tabla de breakers
        """
        html = """
        <tbody>
        """
    
        # Función para renderizar una fila de la tabla con enlace a la ficha técnica
        def render_row(item, description, qty, unit_price, total_price, tech_sheet=None):
            if description is None or description == "" or description == "No":
                return ""
        
            if description in ["Seleccione una opción", "Select an option",
                            "Seleccione un modelo de interrptor", "Select a breaker model"]:
                return ""
        
            # Formatear precios
            formatted_unit_price = format_price(unit_price)
            formatted_total_price = format_price(total_price)
        
            # Si hay ficha técnica, crear un enlace, de lo contrario mostrar solo el texto
            if tech_sheet and tech_sheet.strip():
                item_cell = f'<a href="{tech_sheet}" target="_blank" class="tech-sheet-link">{item or ""}</a>'
            else:
                item_cell = item or ""
        
            return f"""
            <tr>
                <td>{item_cell}</td>
                <td>{description or ""}</td>
                <td>{qty or ""}</td>
                <td>{formatted_unit_price}</td>
                <td>{formatted_total_price}</td>
            </tr>
            """
    
        # Generar filas para cada breaker y sus accesorios
        breakers = CotizacionBreakers_data.get("Breakers", {})
    
        # Breaker 1
        breaker1 = breakers.get("Breaker1", {})
        if breaker1 and breaker1.get("Breaker1") not in [None, "", "Seleccione una opción", "Select an option","Seleccione un modelo de interrptor", "Select a breaker model"]:
            html += render_row(
                breaker1.get("Item_breaker1"),
                breaker1.get("Breaker1"),
                breaker1.get("Breaker1QTYTOT"),
                breaker1.get("Breaker1_Price"),
                breaker1.get("Breaker1_PriceTot"),
                breaker1.get("Breaker1_TSheet")
            )
        
            # Accesorios del Breaker 1
            if "ConfigAndAccesories_Breaker1" in breaker1:
                accessories = breaker1["ConfigAndAccesories_Breaker1"]
            
                # Shunt trip 1
                if accessories.get("Shunt_trip1") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Sunt_t1"),
                        accessories.get("Shunt_trip1DESC"),
                        accessories.get("Shunt_trip1_QTYTOT"),
                        accessories.get("Sunt_t1_Price"),
                        accessories.get("Sunt_t1_PriceTot"),
                        accessories.get("Sunt_t1_TSheet")
                    )
                
                # Shunt trip wiring 1
                if accessories.get("Shunt_trip_wiring1") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Sunt_w1"),
                        accessories.get("Shunt_trip_wiring1DESC"),
                        accessories.get("Shunt_trip_wiring1_QTYTOT"),
                        accessories.get("Sunt_w1_Price"),
                        accessories.get("Sunt_w1_PriceTot"),
                        accessories.get("Sunt_w1_TSheet")
                    )
                
                # GFI 1
                if accessories.get("GFI1") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_GFI1"),
                        accessories.get("Item_GFI1DESC"),
                        accessories.get("Item_GFI1_QTYTOT"),
                        accessories.get("GFI1_Price"),
                        accessories.get("GFI1_PriceTot"),
                        accessories.get("GFI1_TSheet")
                    )
                
                # Protection type 1
                if accessories.get("Protection_type1") not in [None, "", "Seleccione una opción", "Select an option", "Seleccione un modelo de interrptor", "Select a breaker model"]:
                    html += render_row(
                        accessories.get("Item_Proyection_t1"),
                        accessories.get("Protection_type1"),
                        accessories.get("Protection_type1_QTYTOT"),
                        accessories.get("Proyection_t1_Price"),
                        accessories.get("Proyection_t1_PriceTot"),
                        accessories.get("Proyection_t1_TSheet")
                    )
                
                # Auxiliary contacts 1
                if accessories.get("Auxiliary_contacts1") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Auxiliary_c1"),
                        accessories.get("Auxiliary_contactsDESC"),
                        accessories.get("Auxiliary_contacts_QTYTOT"),
                        accessories.get("Auxiliary_c1_Price"),
                        accessories.get("Auxiliary_c1_PriceTot"),
                        accessories.get("Auxiliary_c1_TSheet")
                    )
                
                # Breaker Lock 1
                if accessories.get("Breaker_Lock1") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Breaker_L1"),
                        accessories.get("Breaker_LockDESC"),
                        accessories.get("Breaker_Lock_QTYTOT"),
                        accessories.get("Breaker_L1_Price"),
                        accessories.get("Breaker_L1_PriceTot"),
                        accessories.get("Breaker_L1_TSheet")
                    )
                
                # Motorized Breaker 1
                if accessories.get("Motorized_Breaker1") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Motorized_B1"),
                        accessories.get("Motorized_BreakerDESC"),
                        accessories.get("Motorized_Breaker_QTYTOT"),
                        accessories.get("Motorized_B1_Price"),
                        accessories.get("Motorized_B1_PriceTot"),
                        accessories.get("Motorized_B1_TSheet")
                    )
    
        # Breaker 2
        breaker2 = breakers.get("Breaker2", {})
        if breaker2 and breaker2.get("Breaker2") not in [None, "", "Seleccione una opción", "Select an option","Seleccione un modelo de interrptor", "Select a breaker model"]:
            html += render_row(
                breaker2.get("Item_breaker2"),
                breaker2.get("Breaker2"),
                breaker2.get("Breaker2QTYTOT"),
                breaker2.get("Breaker2_Price"),
                breaker2.get("Breaker2_PriceTot"),
                breaker2.get("Breaker2_TSheet")
            )
        
            # Accesorios del Breaker 2
            if "ConfigAndAccesories_Breaker2" in breaker2:
                accessories = breaker2["ConfigAndAccesories_Breaker2"]
                
                # Shunt trip 2
                if accessories.get("Shunt_trip2") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Sunt_t2"),
                        accessories.get("Shunt_trip2DESC"),
                        accessories.get("Shunt_trip2_QTYTOT"),
                        accessories.get("Sunt_t2_Price"),
                        accessories.get("Sunt_t2_PriceTot"),
                        accessories.get("Sunt_t2_TSheet")
                    )
                
                # Shunt trip wiring 2
                if accessories.get("Shunt_trip_wiring2") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Sunt_w2"),
                        accessories.get("Shunt_trip_wiring2DESC"),
                        accessories.get("Shunt_trip_wiring2_QTYTOT"),
                        accessories.get("Sunt_w2_Price"),
                        accessories.get("Sunt_w2_PriceTot"),
                        accessories.get("Sunt_w2_TSheet")
                    )
                
                # GFI 2
                if accessories.get("GFI2") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_GFI2"),
                        accessories.get("Item_GFI2DESC"),
                        accessories.get("Item_GFI2_QTYTOT"),
                        accessories.get("GFI2_Price"),
                        accessories.get("GFI2_PriceTot"),
                        accessories.get("GFI2_TSheet")
                    )
                
                # Protection type 2
                if accessories.get("Protection_type2") not in [None, "", "Seleccione una opción", "Select an option", "Seleccione un modelo de interrptor", "Select a breaker model"]:
                    html += render_row(
                        accessories.get("Item_Proyection_t2"),
                        accessories.get("Protection_type2"),
                        accessories.get("Protection_type2_QTYTOT"),
                        accessories.get("Proyection_t2_Price"),
                        accessories.get("Proyection_t2_PriceTot"),
                        accessories.get("Proyection_t2_TSheet")
                    )
                
                # Auxiliary contacts 2
                if accessories.get("Auxiliary_contacts2") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Auxiliary_c2"),
                        accessories.get("Auxiliary_contacts2DESC"),
                        accessories.get("Auxiliary_contacts2_QTYTOT"),
                        accessories.get("Auxiliary_c2_Price"),
                        accessories.get("Auxiliary_c2_PriceTot"),
                        accessories.get("Auxiliary_c2_TSheet")
                    )
                
                # Breaker Lock 2
                if accessories.get("Breaker_Lock2") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Breaker_L2"),
                        accessories.get("Breaker_Lock2DESC"),
                        accessories.get("Breaker_Lock2_QTYTOT"),
                        accessories.get("Breaker_L2_Price"),
                        accessories.get("Breaker_L2_PriceTot"),
                        accessories.get("Breaker_L2_TSheet")
                    )
                
                # Motorized Breaker 2
                if accessories.get("Motorized_Breaker2") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Motorized_B2"),
                        accessories.get("Motorized_Breaker2DESC"),
                        accessories.get("Motorized_Breaker2_QTYTOT"),
                        accessories.get("Motorized_B2_Price"),
                        accessories.get("Motorized_B2_PriceTot"),
                        accessories.get("Motorized_B2_TSheet")
                    )
    
        # Breaker 3
        breaker3 = breakers.get("Breaker3", {})
        if breaker3 and breaker3.get("Breaker3") not in [None, "", "Seleccione una opción", "Select an option","Seleccione un modelo de interrptor", "Select a breaker model"]:
            html += render_row(
                breaker3.get("Item_breaker3"),
                breaker3.get("Breaker3"),
                breaker3.get("Breaker3QTYTOT"),
                breaker3.get("Breaker3_Price"),
                breaker3.get("Breaker3_PriceTot"),
                breaker3.get("Breaker3_TSheet")
            )
        
            # Accesorios del Breaker 3
            if "ConfigAndAccesories_Breaker3" in breaker3:
                accessories = breaker3["ConfigAndAccesories_Breaker3"]
                
                # Shunt trip 3
                if accessories.get("Shunt_trip3") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Sunt_t3"),
                        accessories.get("Shunt_trip3DESC"),
                        accessories.get("Shunt_trip3_QTYTOT"),
                        accessories.get("Sunt_t3_Price"),
                        accessories.get("Sunt_t3_PriceTot"),
                        accessories.get("Sunt_t3_TSheet")
                    )
                
                # Shunt trip wiring 3
                if accessories.get("Shunt_trip_wiring3") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Sunt_w3"),
                        accessories.get("Shunt_trip_wiring3DESC"),
                        accessories.get("Shunt_trip_wiring3_QTYTOT"),
                        accessories.get("Sunt_w3_Price"),
                        accessories.get("Sunt_w3_PriceTot"),
                        accessories.get("Sunt_w3_TSheet")
                    )
                
                # GFI 3
                if accessories.get("GFI3") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_GFI3"),
                        accessories.get("Item_GFI3DESC"),
                        accessories.get("Item_GFI3_QTYTOT"),
                        accessories.get("GFI3_Price"),
                        accessories.get("GFI3_PriceTot"),
                        accessories.get("GFI3_TSheet")
                    )
                
                # Protection type 3
                if accessories.get("Protection_type3") not in [None, "", "Seleccione una opción", "Select an option", "Seleccione un modelo de interrptor", "Select a breaker model"]:
                    html += render_row(
                        accessories.get("Item_Proyection_t3"),
                        accessories.get("Protection_type3"),
                        accessories.get("Protection_type3_QTYTOT"),
                        accessories.get("Proyection_t3_Price"),
                        accessories.get("Proyection_t3_PriceTot"),
                        accessories.get("Proyection_t3_TSheet")
                    )
                
                # Auxiliary contacts 3
                if accessories.get("Auxiliary_contacts3") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Auxiliary_c3"),
                        accessories.get("Auxiliary_contacts3DESC"),
                        accessories.get("Auxiliary_contacts3_QTYTOT"),
                        accessories.get("Auxiliary_c3_Price"),
                        accessories.get("Auxiliary_c3_PriceTot"),
                        accessories.get("Auxiliary_c3_TSheet")
                    )
                
                # Breaker Lock 3
                if accessories.get("Breaker_Lock3") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Breaker_L3"),
                        accessories.get("Breaker_Lock3DESC"),
                        accessories.get("Breaker_Lock3_QTYTOT"),
                        accessories.get("Breaker_L3_Price"),
                        accessories.get("Breaker_L3_PriceTot"),
                        accessories.get("Breaker_L3_TSheet")
                    )
                
                # Motorized Breaker 3
                if accessories.get("Motorized_Breaker3") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Motorized_B3"),
                        accessories.get("Motorized_Breaker3DESC"),
                        accessories.get("Motorized_Breaker3_QTYTOT"),
                        accessories.get("Motorized_B3_Price"),
                        accessories.get("Motorized_B3_PriceTot"),
                        accessories.get("Motorized_B3_TSheet")
                    )
    
        html += """
        </tbody>
        """
    
        return html
    
    def Get_CotizacionControl_data(quote_id):
        # Obtener datos de la cotización
        quote_data = get_Definitive_quote_data(quote_id)
        if not quote_data:
            return "Error: No se encontraron datos para la cotización", 404
        
        quote_data = {k: convert_decimal(v) for k, v in quote_data.items()}
        
        #----------------------------CONTROLLER------------------------------
        ControlModelQTY =  quote_data['QtyGenset']
        #SI/NO
        
        CPHDESC = 'Control Panel Heater'
        CPHQTYTOT = quote_data['QtyGenset']

        CMP_CPH_DESCRIPTION = 'Control Panel Heater'
        CMP_CPH_QTYTOTAL = quote_data['QtyGenset']

        DSE2157DESC = 'DSE2157 Output Module  (8 dry contacts)'
        DSE2157QTYTOT = quote_data['QtyDSE2157'] * quote_data['QtyGenset']

        #  CMP-IRB8 Output module para COMAP
        CMP_2157_DESCRIPTION = 'I-RB8 Output module (8 dry contacts)'
        CMP_2157_QTYTOTAL = quote_data['QtyComapDSE2157'] * quote_data['QtyGenset']

        Item_controller_options_DSE2548 = "DSE-2548"
        DSE2548DESC = "DSE2548 Remote Annunciator"
        DSE2548QTYTOT = quote_data['QtyDSE2548'] * quote_data['QtyGenset']

        #  IGLRA15 Remote annunciator para COMAP
        CMP_2548_DESCRIPTION = 'IGL-RA15 Remote Annunciator'
        CMP_2548_QTYTOTOTAL = quote_data['QtyComapDSE2548'] * quote_data['QtyGenset']

        DSE890DESC = 'DSE890 Ethernet/4G gateway device'
        DSE890QTYTOT = quote_data['QtyGenset']

        # CM3-ETHERNET (890) para COMAP
        CMP_890_DESCRIPTION = 'CM3-ETHERNET'
        CMP_890_QTYTOTAL = quote_data['QtyGenset']

        GSM_GSPDESC = 'GSM/GPS ANTENNA 3M RG-174, GSM-SMA(M), GPS-SMA(F)'
        GSM_GSPQTYTOT = quote_data['QtyGenset']

        #  Antena GSM / GPS para COMAP
        CMP_GSM_GSP_DESCRIPTION = 'GSM/GPS ANTENNA 3M RG-174, GSM-SMA(M), GPS-SMA(F)'
        CMP_GSM_GSP_QTYTOTAL = quote_data['QtyGenset']

        RDMDSEDESC = 'Remote Display Module DSE'
        RDMDSEQTYTOT = quote_data['QtyGenset']

        CtrlVotlOperDESC = 'Remote Display Module DSE'
        CtrlVotlOperQTYTOT = quote_data['QtyGenset']

        CMP_RDMDSE_DESCRIPTION = 'Remote Display Module COMAP'
        CMP_RDMDSE_QTYTOTAL = quote_data['QtyGenset']

        BateryChargerQTYTOT = quote_data['QtyGenset']
        
        CotizacionControl_data = {
                "quote_id": quote_id,
                "controller": {
                    # Se coloca si ControlModel es diferente de Seleccione una opcion o Select an option o Selecciona la marca de control o Select the cotroller brand
                    "Item_controller": quote_data['Item_controller'],# ----------------------------Item del ControlModel
                    "ControlModel": quote_data['ControlModel'],# ----------------------------Descripción del ControlModel
                    "ControlModelQTY": ControlModelQTY,# ----------------------------Cantidad total del ControlModel
                    "controller_Price": quote_data['controller_Price'],# ----------------------------Precio unitario del ControlModel
                    "controller_TSheet": quote_data['controller_TSheet'],# ----------------------------Ficha técnica del ControlModel
                    "ControlModel_PriceTot": quote_data['ControlModel_PriceTot'],# ----------------------------Precio total del ControlModel                    
                    "ConfigAndAccesories_Controller": {
                        
                        # Se coloca si CtrlPanelHeater es diferente a No
                        "CtrlPanelHeater": quote_data['Item_CtrlPanelHeater'],# ----------------------------Item del CtrlPanelHeater
                        "CtrlPanelHeater": quote_data['CtrlPanelHeater'],
                        "CPHDESC": CPHDESC,# ----------------------------Descripción del CtrlPanelHeater
                        "CPHQTYTOT": CPHQTYTOT,# ----------------------------Cantidad total del CtrlPanelHeater
                        "CtrlPanelHeater_Price": quote_data['CtrlPanelHeater_Price'],# ----------------------------Precio unitario del CtrlPanelHeater
                        "CtrlPanelHeater_TSheet": quote_data['CtrlPanelHeater_TSheet'],# ----------------------------Ficha técnica del CtrlPanelHeater
                        "CtrlPanelHeat_PriceTot": quote_data['CtrlPanelHeat_PriceTot'],# ----------------------------Precio total del CtrlPanelHeater

                        "Item_CtrlPanelHeaterCMP": quote_data['Item_CtrlPanelHeaterCMP'],
                        "CMP_CPH_DESCRIPTION": CMP_CPH_DESCRIPTION,
                        "CMP_CPH_QTYTOTAL": CMP_CPH_QTYTOTAL,
                        "CtrlPanelHeaterCMP_Price": quote_data['CtrlPanelHeaterCMP_Price'],
                        "CtrlPanelHeaterCMP_TSheet": quote_data['CtrlPanelHeaterCMP_TSheet'],
                        "CtrlPanelHeatCMP_PriceTot": quote_data['CtrlPanelHeatCMP_PriceTot'],


                        # Se coloca si display para COMAP
                        "Item_RempteDisplModCMP": quote_data['Item_RempteDisplModCMP'],
                        "CMP_RDMDSE_DESCRIPTION": CMP_RDMDSE_DESCRIPTION,
                        "CMP_RDMDSE_QTYTOTAL": CMP_RDMDSE_QTYTOTAL,
                        "RempteDisplModCMP_Price": quote_data['RempteDisplModCMP_Price'],
                        "RempteDisplModCMP_TSheet": quote_data['RempteDisplModCMP_TSheet'],
                        "RempteDisplModCMP_PriceTot": quote_data['RempteDisplModCMP_PriceTot'],

                        #  Antena GSM / GPS para COMAP
                        "Item_AntenaCMP": quote_data['Item_AntenaCMP'],
                        "AntenaCMP": quote_data['AntenaCMP'],
                        "CMP_GSM_GSP_DESCRIPTION": CMP_GSM_GSP_DESCRIPTION,
                        "CMP_GSM_GSP_QTYTOTAL": CMP_GSM_GSP_QTYTOTAL,
                        "AntenaCMP_Price": quote_data['AntenaCMP_Price'],
                        "AntenaCMP_TSheet": quote_data['AntenaCMP_TSheet'],
                        "AntenaCMP_PriceTot": quote_data['AntenaCMP_PriceTot'],

                        #  CMP-IRB8 Output module para COMAP
                        "Item_ComapDSE2157": quote_data['Item_ComapDSE2157'],
                        "ComapDSE2157": quote_data['ComapDSE2157'],
                        "CMP_2157_DESCRIPTION": CMP_2157_DESCRIPTION,
                        "CMP_2157_QTYTOTAL": CMP_2157_QTYTOTAL,
                        "ComapDSE2157_Price": quote_data['ComapDSE2157_Price'],
                        "ComapDSE2157_TSheet": quote_data['ComapDSE2157_TSheet'],
                        "ComapDSE2157_PriceTot": quote_data['ComapDSE2157_PriceTot'],

                        #  IGLRA15 Remote annunciator para COMAP
                        "Item_ComapDSE2548": quote_data['Item_ComapDSE2548'],
                        "ComapDSE2548": quote_data['ComapDSE2548'],
                        "CMP_2548_DESCRIPTION": CMP_2548_DESCRIPTION,
                        "CMP_2548_QTYTOTOTAL": CMP_2548_QTYTOTOTAL,
                        "ComapDSE2548_Price": quote_data['ComapDSE2548_Price'],
                        "ComapDSE2548_TSheet": quote_data['ComapDSE2548_TSheet'],
                        "ComapDSE2548_PriceTot": quote_data['ComapDSE2548_PriceTot'],

                        
                        # Se coloca si RemoteDisplayModule es diferente a No
                        "Item_RempteDisplMod": quote_data['Item_RempteDisplMod'],# ----------------------------Item del RemoteDisplayModule
                        "RemoteDisplayModule": quote_data['RemoteDisplayModule'],
                        "RDMDSEDESC": RDMDSEDESC,# ----------------------------Descripción del RemoteDisplayModule
                        "RDMDSEQTYTOT": RDMDSEQTYTOT,# ----------------------------Cantidad total del RemoteDisplayModule
                        "RempteDisplMod_Price": quote_data['RempteDisplMod_Price'],# ----------------------------Precio unitario del RemoteDisplayModule
                        "RempteDisplMod_TSheet": quote_data['RempteDisplMod_TSheet'],# ----------------------------Ficha técnica del RemoteDisplayModule
                        "RempteDisplMod_PriceTot": quote_data['RempteDisplMod_PriceTot'],# ----------------------------Precio total del RemoteDisplayModule

                        "RemoteDisplayModule": quote_data['RemoteDisplayModule'],
                        "RDMDSEDESC": RDMDSEDESC,
                        "RDMDSEQTYTOT": RDMDSEQTYTOT,# ----------------------------Cantidad total del RemoteDisplayModule
                        "RempteDisplMod_Price": quote_data['RempteDisplMod_Price'],# ----------------------------Precio unitario del RemoteDisplayModule
                        "RempteDisplMod_TSheet": quote_data['RempteDisplMod_TSheet'],# ----------------------------Ficha técnica del RemoteDisplayModule
                        "RempteDisplMod_PriceTot": quote_data['RempteDisplMod_PriceTot'],# ----------------------------Precio total del RemoteDisplayModule
                        
                        # Se coloca si Antena es diferente a No
                        "Item_Antena": quote_data['Item_Antena'],# ----------------------------Item del Antena
                        "Antena": quote_data['Antena'],
                        "GSM_GSPDESC": GSM_GSPDESC,# ----------------------------Descripción del Antena
                        "GSM_GSPQTYTOT": GSM_GSPQTYTOT,# ----------------------------Cantidad total del Antena
                        "Antena_Price": quote_data['Antena_Price'],# ----------------------------Precio unitario del Antena
                        "Antena_TSheet": quote_data['Antena_TSheet'],# ----------------------------Ficha técnica del Antena
                        "Antena_PriceTot": quote_data['Antena_PriceTot'],# ----------------------------Precio total del Antena
                        
                        "ConfigAndAccesories_DeepSea": {
                            
                            # Se coloca si DSE890 es diferente a No
                            "Item_DSE890": quote_data['Item_DSE890'],# ----------------------------Item del DSE890
                            "DSE890": quote_data['DSE890'],
                            "DSE890DESC": DSE890DESC,# ----------------------------Descripción del DSE890
                            "DSE890QTYTOT": DSE890QTYTOT,# ----------------------------Cantidad total del DSE890
                            "DSE890_Price": quote_data['DSE890_Price'],# ----------------------------Precio unitario del DSE890
                            "DSE890_TSheet": quote_data['DSE890_TSheet'],# ----------------------------Ficha técnica del DSE890
                            "DSE890_PriceTot": quote_data['DSE890_PriceTot'],# ----------------------------Precio total del DSE890

                                # CM3-ETHERNET (890) para COMAP
                            "Item_ComapDSE890": quote_data['Item_ComapDSE890'],
                            "CMP_890_DESCRIPTION": CMP_890_DESCRIPTION,
                            "CMP_890_QTYTOTAL": CMP_890_QTYTOTAL,
                            "ComapDSE890_Price": quote_data['ComapDSE890_Price'],
                            "ComapDSE890_TSheet": quote_data['ComapDSE890_TSheet'],
                            "ComapDSE890_PriceTot": quote_data['ComapDSE890_PriceTot'],

                            
                            # Se coloca si DSE2157 es diferente a No
                            "Item_DSE2157": quote_data['Item_DSE2157'],# ----------------------------Item del DSE2157
                            "DSE2157": quote_data['DSE2157'],
                            "QtyDSE2157": quote_data['QtyDSE2157'],
                            "DSE2157DESC": DSE2157DESC,# ----------------------------Descripción del DSE2157
                            "DSE2157QTYTOT": DSE2157QTYTOT,# ----------------------------Cantidad total del DSE2157
                            "DSE2157_Price": quote_data['DSE2157_Price'],# ----------------------------Precio unitario del DSE2157
                            "DSE2157_TSheet": quote_data['DSE2157_TSheet'],# ----------------------------Ficha técnica del DSE2157
                            "DSE2157_PriceTot": quote_data['DSE2157_PriceTot'],# ----------------------------Precio total del DSE2157
                            
                            # Se coloca si DSE2548 es diferente a No
                            "Item_DSE2548": quote_data['Item_DSE2548'],# ----------------------------Item del DSE2548
                            "DSE2548": quote_data['DSE2548'],
                            "QtyDSE2548": quote_data['QtyDSE2548'],
                            "DSE2548DESC": DSE2548DESC,# ----------------------------Descripción del DSE2548
                            "DSE2548QTYTOT": DSE2548QTYTOT,# ----------------------------Cantidad total del DSE2548
                            "DSE2548_Price": quote_data['DSE2548_Price'],# ----------------------------Precio unitario del DSE2548
                            "DSE2548_TSheet": quote_data['DSE2548_TSheet'],# ----------------------------Ficha técnica del DSE2548
                            "DSE2548_PriceTot": quote_data['DSE2548_PriceTot'],# ----------------------------Precio total del DSE2548
                        },
                        
                        # Se coloca si CtrlVotlOper es diferente de Seleccione una opcion o Select an option
                        "Item_CtrlVotlOper": quote_data['Item_CtrlVotlOper'],# ----------------------------Item del CtrlVotlOper
                        "CtrlVotlOper": quote_data['CtrlVotlOper'],
                        "CtrlVotlOperDESC": CtrlVotlOperDESC,# ----------------------------Descripción del CtrlVotlOper
                        "CtrlVotlOperQTYTOT": CtrlVotlOperQTYTOT,# ----------------------------Cantidad total del CtrlVotlOper
                        "CtrlVotlOper_Price": quote_data['CtrlVotlOper_Price'],# ----------------------------Precio unitario del CtrlVotlOper
                        "CtrlVotlOper_TSheet": quote_data['CtrlVotlOper_TSheet'],# ----------------------------Ficha técnica del CtrlVotlOper
                        "CtrlVotlOper_PriceTot": quote_data['CtrlVotlOper_PriceTot'],# ----------------------------Precio total del CtrlVotlOper
                        
                        # Se coloca si BateryCharger es diferente a No
                        "Item_BateryCharger": quote_data['Item_BateryCharger'],# ----------------------------Item del BateryCharger
                        "BateryCharger": quote_data['BateryCharger'],# ----------------------------Descripción del BateryCharger
                        "BateryChargerQTYTOT": BateryChargerQTYTOT,# ----------------------------Cantidad total del BateryCharger
                        "BateryCharger_Price": quote_data['BateryCharger_Price'],# ----------------------------Precio unitario del BateryCharger
                        "BateryCharger_TSheet": quote_data['BateryCharger_TSheet'],# ----------------------------Ficha técnica del BateryCharger
                        "BateryCharger_PriceTot": quote_data['BateryCharger_PriceTot']# ----------------------------Precio total del BateryCharger
                    }
                }
            }
        
        return CotizacionControl_data
    def generate_quote_table_Control(CotizacionControl_data):
        """
        Genera el HTML para la tabla de controladores con enlaces a fichas técnicas
    
        Args:
            CotizacionControl_data (dict): Datos de los controladores
        
        Returns:
            str: HTML para la tabla de controladores
        """
        html = """
        <tbody>
        """
    
        # Función para renderizar una fila de la tabla con enlace a la ficha técnica
        def render_row(item, description, qty, unit_price, total_price, tech_sheet=None):
            if description is None or description == "" or description == "No":
                return ""
        
            if description in ["Seleccione una opción", "Select an option",
                            "Selecciona la marca de control", "Select the cotroller brand"]:
                return ""
        
            # Formatear precios
            formatted_unit_price = format_price(unit_price)
            formatted_total_price = format_price(total_price)
        
            # Si hay ficha técnica, crear un enlace, de lo contrario mostrar solo el texto
            if tech_sheet and tech_sheet.strip():
                item_cell = f'<a href="{tech_sheet}" target="_blank" class="tech-sheet-link">{item or ""}</a>'
            else:
                item_cell = item or ""
        
            return f"""
            <tr>
                <td>{item_cell}</td>
                <td>{description or ""}</td>
                <td>{qty or ""}</td>
                <td>{formatted_unit_price}</td>
                <td>{formatted_total_price}</td>
            </tr>
            """
    
        # Obtener datos del controlador
        controller = CotizacionControl_data.get("controller", {})
        
        # Controlador principal
        if controller and controller.get("ControlModel") not in [None, "", "Seleccione una opción", "Select an option", 
                                                                "Selecciona la marca de control", "Select the cotroller brand"]:
            html += render_row(
                controller.get("Item_controller"),
                controller.get("ControlModel"),
                controller.get("ControlModelQTY"),
                controller.get("controller_Price"),
                controller.get("ControlModel_PriceTot"),
                controller.get("controller_TSheet")
            )
            
            # Accesorios del controlador
            if "ConfigAndAccesories_Controller" in controller:
                accessories = controller["ConfigAndAccesories_Controller"]
                
                # Panel Heater
                if accessories.get("CtrlPanelHeater") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_CtrlPanelHeater"),
                        accessories.get("CPHDESC"),
                        accessories.get("CPHQTYTOT"),
                        accessories.get("CtrlPanelHeater_Price"),
                        accessories.get("CtrlPanelHeat_PriceTot"),
                        accessories.get("CtrlPanelHeater_TSheet")
                    )

                # Panel Heater cmp
                if accessories.get("Item_CtrlPanelHeaterCMP") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_CtrlPanelHeaterCMP"),
                        accessories.get("CMP_CPH_DESCRIPTION"),
                        accessories.get("CMP_CPH_QTYTOTAL"),
                        accessories.get("CtrlPanelHeaterCMP_Price"),
                        accessories.get("CtrlPanelHeatCMP_PriceTot"),
                        accessories.get("CtrlPanelHeaterCMP_TSheet")
                    )

                


                # Remote Display Module
                if accessories.get("RemoteDisplayModule") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_RempteDisplMod"),
                        accessories.get("RDMDSEDESC"),
                        accessories.get("RDMDSEQTYTOT"),
                        accessories.get("RempteDisplMod_Price"),
                        accessories.get("RempteDisplMod_PriceTot"),
                        accessories.get("RempteDisplMod_TSheet")
                    )

                # Panel DISPLAY CMP
                if accessories.get("Item_RempteDisplModCMP") not in [None, "", "No"]:
                    html += render_row(
                            accessories.get("Item_RempteDisplModCMP"),
                            accessories.get("CMP_RDMDSE_DESCRIPTION"),
                            accessories.get("CMP_RDMDSE_QTYTOTAL"),
                            accessories.get("RempteDisplModCMP_Price"),
                            accessories.get("RempteDisplModCMP_PriceTot"),
                            accessories.get("RempteDisplModCMP_TSheet")
                    )


                # Antena
                if accessories.get("Antena") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Antena"),
                        accessories.get("GSM_GSPDESC"),
                        accessories.get("GSM_GSPQTYTOT"),
                        accessories.get("Antena_Price"),
                        accessories.get("Antena_PriceTot"),
                        accessories.get("Antena_TSheet")
                    )

                # Antena CMP
                if accessories.get("AntenaCMP") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_AntenaCMP"),
                        accessories.get("CMP_GSM_GSP_DESCRIPTION"),
                        accessories.get("CMP_GSM_GSP_QTYTOTAL"),
                        accessories.get("AntenaCMP_Price"),
                        accessories.get("AntenaCMP_PriceTot"),
                        accessories.get("AntenaCMP_TSheet")
                    )


                # Accesorios específicos de DeepSea
                if "ConfigAndAccesories_DeepSea" in accessories:
                    deep_sea = accessories["ConfigAndAccesories_DeepSea"]
                    
                    # DSE890
                    if deep_sea.get("DSE890") not in [None, "", "No"]:
                        html += render_row(
                            deep_sea.get("Item_DSE890"),
                            deep_sea.get("DSE890DESC"),
                            deep_sea.get("DSE890QTYTOT"),
                            deep_sea.get("DSE890_Price"),
                            deep_sea.get("DSE890_PriceTot"),
                            deep_sea.get("DSE890_TSheet")
                        )

                    # CM3 Ethernet / 4G gateway device
                    if deep_sea.get("Item_ComapDSE890") not in [None, "", "No"]:
                        html += render_row(
                            deep_sea.get("Item_ComapDSE890"),
                            deep_sea.get("CMP_890_DESCRIPTION"),
                            deep_sea.get("CMP_890_QTYTOTAL"),
                            deep_sea.get("ComapDSE890_Price"),
                            deep_sea.get("ComapDSE890_PriceTot"),
                            deep_sea.get("ComapDSE890_TSheet")
                        )
                    
                    # DSE2157
                    if deep_sea.get("DSE2157") not in [None, "", "No"]:
                        html += render_row(
                            deep_sea.get("Item_DSE2157"),
                            deep_sea.get("DSE2157DESC"),
                            deep_sea.get("DSE2157QTYTOT"),
                            deep_sea.get("DSE2157_Price"),
                            deep_sea.get("DSE2157_PriceTot"),
                            deep_sea.get("DSE2157_TSheet")
                        )

                    # Comap dse2157 CMP-IRB8 Output module
                    if accessories.get("ComapDSE2157") not in [None, "", "No"]:
                        html += render_row(
                            accessories.get("Item_ComapDSE2157"),
                            accessories.get("CMP_2157_DESCRIPTION"),
                            accessories.get("CMP_2157_QTYTOTAL"),
                            accessories.get("ComapDSE2157_Price"),
                            accessories.get("ComapDSE2157_PriceTot"),
                            accessories.get("ComapDSE2157_TSheet")
                        )
                    
                    # DSE2548
                    if deep_sea.get("DSE2548") not in [None, "", "No"]:
                        html += render_row(
                            deep_sea.get("Item_DSE2548"),
                            deep_sea.get("DSE2548DESC"),
                            deep_sea.get("DSE2548QTYTOT"),
                            deep_sea.get("DSE2548_Price"),
                            deep_sea.get("DSE2548_PriceTot"),
                            deep_sea.get("DSE2548_TSheet")
                        )
                    
                    
                    # IGLRA15 Remote annunciator
                    if accessories.get("ComapDSE2548") not in [None, "", "No"]:
                        html += render_row(
                            accessories.get("Item_ComapDSE2548"),
                            accessories.get("CMP_2548_DESCRIPTION"),
                            accessories.get("CMP_2548_QTYTOTOTAL"),
                            accessories.get("ComapDSE2548_Price"),
                            accessories.get("ComapDSE2548_PriceTot"),
                            accessories.get("ComapDSE2548_TSheet")
                        )
                        
                # CtrlVotlOper (Voltaje de operación del controlador)
                if accessories.get("CtrlVotlOper") not in [None, "", "Seleccione una opción", "Select an option"]:
                    html += render_row(
                        accessories.get("Item_CtrlVotlOper"),
                        accessories.get("CtrlVotlOperDESC"),
                        accessories.get("CtrlVotlOperQTYTOT"),
                        accessories.get("CtrlVotlOper_Price"),
                        accessories.get("CtrlVotlOper_PriceTot"),
                        accessories.get("CtrlVotlOper_TSheet")
                    )
                    
                # BateryCharger (Cargador de batería)
                if accessories.get("BateryCharger") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_BateryCharger"),
                        accessories.get("BateryCharger"),
                        accessories.get("BateryChargerQTYTOT"),
                        accessories.get("BateryCharger_Price"),
                        accessories.get("BateryCharger_PriceTot"),
                        accessories.get("BateryCharger_TSheet")
                    )
        
        html += """
        </tbody>
        """
        
        return html
    
    def Get_CotizacionAccesories_data(quote_id):
        # Obtener datos de la cotización
        quote_data = get_Definitive_quote_data(quote_id)
        if not quote_data:
            return "Error: No se encontraron datos para la cotización", 404
        
        quote_data = {k: convert_decimal(v) for k, v in quote_data.items()}
        
        #------------------------ADITIONAL ACCESORIES-INSTALLED-------------------------

        BandHeaterDESC = 'Alternator strip heater'
        BandHeaterQTYTOT = quote_data['QtyGenset']
        
        PMGUpdateDESC = 'MX321 - PMG Upgrade'
        PMGUpdateQTYTOT = quote_data['QtyGenset']

        DigitalRegulatorDESC = 'DM110 Digital voltage regulator'
        DigitalRegulatorQTYTOT = quote_data['QtyGenset']

        VoltageRheostatDESC = 'Voltage adjust rheostat'
        VoltageRheostatQTYTOT = quote_data['QtyGenset']

        ThermalWrapDESC = 'Battery thermal wrap'
        ThermalWrapQTYTOT = quote_data['QtyGenset']

        BaseHeaterDESC = 'Battery pad heater'
        BaseHeaterQTYTOT = quote_data['QtyGenset']

        BatterySwitchDESC = 'Battery disconnect switch'
        BatterySwitchQTYTOT = quote_data['QtyGenset']

        BatteryHolderDESC = 'Battery restraint'
        BatteryHolderQTYTOT = quote_data['QtyGenset']

        OilHeaterDESC = 'Oil pan heater'
        OilHeaterQTYTOT = quote_data['QtyGenset']

        OilLevelSwitchDESC = 'Oil level switch-murphy 129'
        OilLevelSwitchQTYTOT = quote_data['QtyGenset']

        CommonAlarmRelayDESC = 'Relay - 10A Common alarm'
        CommonAlarmRelayQTYTOT = quote_data['QtyGenset']

        FunctionRelayDESC = 'Relay - 10A Run relay'
        FunctionRelayQTYTOT = quote_data['QtyGenset']

        CoolantDESC = 'Coolant in Gen-set'
        CoolantQTYTOT = quote_data['QtyGenset']

        OilDESC = 'Oil in Gen-Set'
        OilQTYTOT = quote_data['QtyGenset']

        DisconnectSwitchesDESC = 'Heater Disconnect Switches'
        DisconnectSwitchesQTYTOT = quote_data['QtyGenset']

        EStopQTYTOT =  quote_data['QtyGenset'] #MULTIPLICAR Item_AddAccesory_Estop

        RemoteEStopDESC = 'Remote E-Stop - Visual / Plastic hinged cover'
        RemoteEStopQTYTOT = quote_data['QtyGenset']

        SpringIsolatorQTYTOT = quote_data['QtyGenset']
        
        CotizacionAccesories_data = {
                "quote_id": quote_id,
                "AdditionalAccesories_Genset": {
                    # Se coloca si BandHeater es diferente a No
                    "Item_BandHeater": quote_data['Item_BandHeater'],# ----------------------------Item del BandHeater
                    "BandHeater": quote_data['BandHeater'],
                    "BandHeaterQTYTOT": BandHeaterQTYTOT,# ----------------------------Cantidad total del BandHeater
                    "BandHeaterDESC": BandHeaterDESC,# ----------------------------Descripción del BandHeater
                    "BandHeater_Price": quote_data['BandHeater_Price'],# ----------------------------Precio unitario del BandHeater
                    "BandHeater_TSheet": quote_data['BandHeater_TSheet'],# ----------------------------Ficha técnica del BandHeater
                    "BandHeater_PriceTot": quote_data['BandHeater_PriceTot'],# ----------------------------Precio total del BandHeater

                    # Se coloca si PMGUpdate es diferente a No
                    "Item_PMGUpdate": quote_data['Item_PMGUpdate'],# ----------------------------Item del PMGUpdate
                    "PMGUpdate": quote_data['PMGUpdate'],
                    "PMGUpdateQTYTOT": PMGUpdateQTYTOT,# ----------------------------Cantidad total del PMGUpdate
                    "PMGUpdateDESC":PMGUpdateDESC,# ----------------------------Descripción del PMGUpdate
                    "PMGUpdate_Price": quote_data['PMGUpdate_Price'],# ----------------------------Precio unitario del PMGUpdate
                    "PMGUpdate_TSheet": quote_data['PMGUpdate_TSheet'],# ----------------------------Ficha técnica del PMGUpdate
                    "PMGUpdate_PriceTot": quote_data['PMGUpdate_PriceTot'],# ----------------------------Precio total del PMGUpdate

                    # Se coloca si DigitalRegulator es diferente a No
                    "Item_DigitalRegulator": quote_data['Item_DigitalRegulator'],# ----------------------------Item del DigitalRegulator
                    "DigitalRegulator": quote_data['DigitalRegulator'],
                    "DigitalRegulatorQTYTOT": DigitalRegulatorQTYTOT,# ----------------------------Cantidad total del DigitalRegulator
                    "DigitalRegulatorDESC": DigitalRegulatorDESC,# ----------------------------Descripción del DigitalRegulator
                    "DigitalRegulator_Price": quote_data['DigitalRegulator_Price'],# ----------------------------Precio unitario del DigitalRegulator
                    "DigitalRegulator_TSheet": quote_data['DigitalRegulator_TSheet'],# ----------------------------Ficha técnica del DigitalRegulator
                    "DigitalRegulat_PriceTot": quote_data['DigitalRegulat_PriceTot'],# ----------------------------Precio total del DigitalRegulator

                    # Se coloca si VoltageRheostat es diferente a No
                    "Item_VoltageRheostat": quote_data['Item_VoltageRheostat'],# ----------------------------Item del VoltageRheostat
                    "VoltageRheostat": quote_data['VoltageRheostat'],
                    "VoltageRheostatQTYTOT": VoltageRheostatQTYTOT,# ----------------------------Cantidad total del VoltageRheostat
                    "VoltageRheostatDESC": VoltageRheostatDESC,# ----------------------------Descripción del VoltageRheostat
                    "VoltageRheostat_Price": quote_data['VoltageRheostat_Price'],# ----------------------------Precio unitario del VoltageRheostat
                    "VoltageRheostat_TSheet": quote_data['VoltageRheostat_TSheet'],# ----------------------------Ficha técnica del VoltageRheostat
                    "VoltageRheosta_PriceTot": quote_data['VoltageRheosta_PriceTot'],# ----------------------------Precio total del VoltageRheostat

                    # Se coloca si ThermalWrap es diferente a No
                    "Item_ThermalWrap": quote_data['Item_ThermalWrap'],# ----------------------------Item del ThermalWrap
                    "ThermalWrap": quote_data['ThermalWrap'],
                    "ThermalWrapQTYTOT": ThermalWrapQTYTOT,# ----------------------------Cantidad total del ThermalWrap
                    "ThermalWrapDESC": ThermalWrapDESC,# ----------------------------Descripción del ThermalWrap
                    "ThermalWrap_Price": quote_data['ThermalWrap_Price'],# ----------------------------Precio unitario del ThermalWrap
                    "ThermalWrap_TSheet": quote_data['ThermalWrap_TSheet'],# ----------------------------Ficha técnica del ThermalWrap
                    "ThermalWrap_PriceTot": quote_data['ThermalWrap_PriceTot'],# ----------------------------Precio total del ThermalWrap

                    # Se coloca si BaseHeater es diferente a No
                    "Item_BaseHeater": quote_data['Item_BaseHeater'],# ----------------------------Item del BaseHeater
                    "BaseHeater": quote_data['BaseHeater'],
                    "BaseHeaterQTYTOT": BaseHeaterQTYTOT,# ----------------------------Cantidad total del BaseHeater
                    "BaseHeaterDESC": BaseHeaterDESC,# ----------------------------Descripción del BaseHeater
                    "BaseHeater_Price": quote_data['BaseHeater_Price'],# ----------------------------Precio unitario del BaseHeater
                    "BaseHeater_TSheet": quote_data['BaseHeater_TSheet'],# ----------------------------Ficha técnica del BaseHeater
                    "BaseHeater_PriceTot": quote_data['BaseHeater_PriceTot'],# ----------------------------Precio total del BaseHeater

                    # Se coloca si BatterySwitch es diferente a No
                    "Item_BatterySwitch": quote_data['Item_BatterySwitch'],# ----------------------------Item del BatterySwitch
                    "BatterySwitch": quote_data['BatterySwitch'],
                    "BatterySwitchQTYTOT": BatterySwitchQTYTOT,# ----------------------------Cantidad total del BatterySwitch
                    "BatterySwitchDESC": BatterySwitchDESC,# ----------------------------Descripción del BatterySwitch
                    "BatterySwitch_Price": quote_data['BatterySwitch_Price'],# ----------------------------Precio unitario del BatterySwitch
                    "BatterySwitch_TSheet": quote_data['BatterySwitch_TSheet'],# ----------------------------Ficha técnica del BatterySwitch
                    "BatterySwitch_PriceTot": quote_data['BatterySwitch_PriceTot'],# ----------------------------Precio total del BatterySwitch

                    # Se coloca si BatteryHolder es diferente a No
                    "Item_BatteryHolder": quote_data['Item_BatteryHolder'],# ----------------------------Item del BatteryHolder
                    "BatteryHolder": quote_data['BatteryHolder'],
                    "BatteryHolderQTYTOT": BatteryHolderQTYTOT,# ----------------------------Cantidad total del BatteryHolder
                    "BatteryHolderDESC": BatteryHolderDESC,# ----------------------------Descripción del BatteryHolder
                    "BatteryHolder_Price": quote_data['BatteryHolder_Price'],# ----------------------------Precio unitario del BatteryHolder
                    "BatteryHolder_TSheet": quote_data['BatteryHolder_TSheet'],# ----------------------------Ficha técnica del BatteryHolder
                    "BatteryHolder_PriceTot": quote_data['BatteryHolder_PriceTot'],# ----------------------------Precio total del BatteryHolder

                    # Se coloca si OilHeater es diferente a No
                    "Item_OilHeater": quote_data['Item_OilHeater'],# ----------------------------Item del OilHeater
                    "OilHeater": quote_data['OilHeater'],
                    "OilHeaterQTYTOT": OilHeaterQTYTOT,# ----------------------------Cantidad total del OilHeater
                    "OilHeaterDESC": OilHeaterDESC,# ----------------------------Descripción del OilHeater
                    "OilHeater_Price": quote_data['OilHeater_Price'],# ----------------------------Precio unitario del OilHeater
                    "OilHeater_TSheet": quote_data['OilHeater_TSheet'],# ----------------------------Ficha técnica del OilHeater
                    "OilHeater_PriceTot": quote_data['OilHeater_PriceTot'],# ----------------------------Precio total del OilHeater

                    # Se coloca si OilLevelSwitch es diferente a No
                    "Item_OilLevelSwitch": quote_data['Item_OilLevelSwitch'],# ----------------------------Item del OilLevelSwitch
                    "OilLevelSwitch": quote_data['OilLevelSwitch'],
                    "OilLevelSwitchQTYTOT": OilLevelSwitchQTYTOT,# ----------------------------Cantidad total del OilLevelSwitch
                    "OilLevelSwitchDESC": OilLevelSwitchDESC,# ----------------------------Descripción del OilLevelSwitch
                    "OilLevelSwitch_Price": quote_data['OilLevelSwitch_Price'],# ----------------------------Precio unitario del OilLevelSwitch
                    "OilLevelSwitch_TSheet": quote_data['OilLevelSwitch_TSheet'],# ----------------------------Ficha técnica del OilLevelSwitch
                    "OilLevelSwitch_PriceTot": quote_data['OilLevelSwitch_PriceTot'],# ----------------------------Precio total del OilLevelSwitch

                    # Se coloca si CommonAlarmRelay es diferente a No
                    "Item_CommonAlarmRelay": quote_data['Item_CommonAlarmRelay'],# ----------------------------Item del CommonAlarmRelay
                    "CommonAlarmRelay": quote_data['CommonAlarmRelay'],
                    "CommonAlarmRelayQTYTOT": CommonAlarmRelayQTYTOT,# ----------------------------Cantidad total del CommonAlarmRelay
                    "CommonAlarmRelayDESC": CommonAlarmRelayDESC,# ----------------------------Descripción del CommonAlarmRelay
                    "CommonAlarmRelay_Price": quote_data['CommonAlarmRelay_Price'],# ----------------------------Precio unitario del CommonAlarmRelay
                    "CommonAlarmRelay_TSheet": quote_data['CommonAlarmRelay_TSheet'],# ----------------------------Ficha técnica del CommonAlarmRelay
                    "CommonAlarmRel_PriceTot": quote_data['CommonAlarmRel_PriceTot'],# ----------------------------Precio total del CommonAlarmRelay

                    # Se coloca si FunctionRelay es diferente a No
                    "Item_FunctionRelay": quote_data['Item_FunctionRelay'],# ----------------------------Item del FunctionRelay
                    "FunctionRelay": quote_data['FunctionRelay'],
                    "FunctionRelayQTYTOT": FunctionRelayQTYTOT,# ----------------------------Cantidad total del FunctionRelay
                    "FunctionRelayDESC": FunctionRelayDESC,# ----------------------------Descripción del FunctionRelay
                    "FunctionRelay_Price": quote_data['FunctionRelay_Price'],# ----------------------------Precio unitario del FunctionRelay
                    "FunctionRelay_TSheet": quote_data['FunctionRelay_TSheet'],# ----------------------------Ficha técnica del FunctionRelay
                    "FunctionRelay_PriceTot": quote_data['FunctionRelay_PriceTot'],# ----------------------------Precio total del FunctionRelay

                    # Se coloca si Coolant es diferente a No
                    "Item_Coolant": quote_data['Item_Coolant'],# ----------------------------Item del Coolant
                    "Coolant": quote_data['Coolant'],
                    "CoolantQTYTOT": CoolantQTYTOT,# ----------------------------Cantidad total del Coolant
                    "CoolantDESC": CoolantDESC,# ----------------------------Descripción del Coolant
                    "Coolant_Price": quote_data['Coolant_Price'],# ----------------------------Precio unitario del Coolant
                    "Coolant_TSheet": quote_data['Coolant_TSheet'],# ----------------------------Ficha técnica del Coolant
                    "Coolant_PriceTot": quote_data['Coolant_PriceTot'],# ----------------------------Precio total del Coolant

                    # Se coloca si Oil es diferente a No
                    "Item_Oil": quote_data['Item_Oil'],# ----------------------------Item del Oil
                    "Oil": quote_data['Oil'],
                    "OilQTYTOT": OilQTYTOT,# ----------------------------Cantidad total del Oil
                    "OilDESC": OilDESC,# ----------------------------Descripción del Oil
                    "Oil_Price": quote_data['Oil_Price'],# ----------------------------Precio unitario del Oil
                    "Oil_TSheet": quote_data['Oil_TSheet'],# ----------------------------Ficha técnica del Oil
                    "Oil_PriceTot": quote_data['Oil_PriceTot'],# ----------------------------Precio total del Oil

                    # Se coloca si DisconnectSwitches es diferente a No
                    "Item_DisconnectSwitches": quote_data['Item_DisconnectSwitches'],# ----------------------------Item del DisconnectSwitches
                    "DisconnectSwitches": quote_data['DisconnectSwitches'],
                    "DisconnectSwitchesQTYTOT": DisconnectSwitchesQTYTOT,# ----------------------------Cantidad total del DisconnectSwitches
                    "DisconnectSwitchesDESC": DisconnectSwitchesDESC,# ----------------------------Descripción del DisconnectSwitches
                    "DisconnectSwitch_Price": quote_data['DisconnectSwitch_Price'],# ----------------------------Precio unitario del DisconnectSwitches
                    "DisconnectSwitch_TSheet": quote_data['DisconnectSwitch_TSheet'],# ----------------------------Ficha técnica del DisconnectSwitches
                    "DisconnectSwit_PriceTot": quote_data['DisconnectSwit_PriceTot'],# ----------------------------Precio total del DisconnectSwitches

                    # Se coloca si EStop es diferente de Seleccione una opcion o Select an option 
                    "Item_AddAccesory_Estop": quote_data['Item_AddAccesory_Estop'],# ----------------------------Item del EStop
                    "EStop": quote_data['EStop'],# ----------------------------Descripción del EStop
                    "QtyEStop": quote_data['QtyEStop'],
                    "EStopQTYTOT": EStopQTYTOT,# ----------------------------Cantidad total del EStop
                    "EStop_price": quote_data['EStop_price'],# ----------------------------Precio unitario del EStop
                    "EStop_TSheet": quote_data['EStop_TSheet'],# ----------------------------Ficha técnica del EStop
                    "EStop_PriceTot": quote_data['EStop_PriceTot'],# ----------------------------Precio total del EStop
                    
                    # Se coloca si RemoteEStop es diferente a No
                    "Item_RemoteEStop": quote_data['Item_RemoteEStop'],# ----------------------------Item del RemoteEStop
                    "RemoteEStop": quote_data['RemoteEStop'],
                    "RemoteEStopQTYTOT": RemoteEStopQTYTOT,# ----------------------------Cantidad total del RemoteEStop
                    "RemoteEStopDESC": RemoteEStopDESC,# ----------------------------Descripción del RemoteEStop
                    "RemoteEStop_Price": quote_data['RemoteEStop_Price'],# ----------------------------Precio unitario del RemoteEStop
                    "RemoteEStop_TSheet": quote_data['RemoteEStop_TSheet'],# ----------------------------Ficha técnica del RemoteEStop
                    "RemoteEStop_PriceTot": quote_data['RemoteEStop_PriceTot'],# ----------------------------Precio total del RemoteEStop

                    # Se coloca si SpringIsolator es diferente de Seleccione una opcion o Select an option 
                    "Item_AddAccesory_Spring": quote_data['Item_AddAccesory_Spring'],# ----------------------------Item del SpringIsolator
                    "SpringIsolator": quote_data['SpringIsolator'],# ----------------------------Descripción del SpringIsolator
                    "SpringIsolatorQTYTOT": SpringIsolatorQTYTOT,# ----------------------------Cantidad total del SpringIsolator
                    "SpringIsolator_price": quote_data['SpringIsolator_price'],# ----------------------------Precio unitario del SpringIsolator
                    "SpringIsolator_TSheet": quote_data['SpringIsolator_TSheet'],# ----------------------------Ficha técnica del SpringIsolator
                    "SpringIsolator_PriceTot": quote_data['SpringIsolator_PriceTot']# ----------------------------Precio total del SpringIsolator
                },
            }
        
        return CotizacionAccesories_data
    def generate_quote_table_Accesories(CotizacionAccesories_data):
        """
        Genera el HTML para la tabla de accesorios adicionales con enlaces a fichas técnicas
    
        Args:
            CotizacionAccesories_data (dict): Datos de los accesorios adicionales
        
        Returns:
            str: HTML para la tabla de accesorios adicionales
        """
        html = """
        <tbody>
        """
    
        # Función para renderizar una fila de la tabla con enlace a la ficha técnica
        def render_row(item, description, qty, unit_price, total_price, tech_sheet=None):
            if description is None or description == "" or description == "No":
                return ""
        
            if description in ["Seleccione una opción", "Select an option"]:
                return ""
        
            # Formatear precios
            formatted_unit_price = format_price(unit_price)
            formatted_total_price = format_price(total_price)
        
            # Si hay ficha técnica, crear un enlace, de lo contrario mostrar solo el texto
            if tech_sheet and tech_sheet.strip():
                item_cell = f'<a href="{tech_sheet}" target="_blank" class="tech-sheet-link">{item or ""}</a>'
            else:
                item_cell = item or ""
        
            return f"""
            <tr>
                <td>{item_cell}</td>
                <td>{description or ""}</td>
                <td>{qty or ""}</td>
                <td>{formatted_unit_price}</td>
                <td>{formatted_total_price}</td>
            </tr>
            """
    
        # Obtener datos de accesorios adicionales
        accessories = CotizacionAccesories_data.get("AdditionalAccesories_Genset", {})
        
        # BandHeater
        if accessories.get("BandHeater") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_BandHeater"),
                accessories.get("BandHeaterDESC"),
                accessories.get("BandHeaterQTYTOT"),
                accessories.get("BandHeater_Price"),
                accessories.get("BandHeater_PriceTot"),
                accessories.get("BandHeater_TSheet")
            )
        
        # PMGUpdate
        if accessories.get("PMGUpdate") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_PMGUpdate"),
                accessories.get("PMGUpdateDESC"),
                accessories.get("PMGUpdateQTYTOT"),
                accessories.get("PMGUpdate_Price"),
                accessories.get("PMGUpdate_PriceTot"),
                accessories.get("PMGUpdate_TSheet")
            )
        
        # DigitalRegulator
        if accessories.get("DigitalRegulator") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_DigitalRegulator"),
                accessories.get("DigitalRegulatorDESC"),
                accessories.get("DigitalRegulatorQTYTOT"),
                accessories.get("DigitalRegulator_Price"),
                accessories.get("DigitalRegulat_PriceTot"),  # Note el nombre diferente aquí
                accessories.get("DigitalRegulator_TSheet")
            )
        
        # VoltageRheostat
        if accessories.get("VoltageRheostat") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_VoltageRheostat"),
                accessories.get("VoltageRheostatDESC"),
                accessories.get("VoltageRheostatQTYTOT"),
                accessories.get("VoltageRheostat_Price"),
                accessories.get("VoltageRheosta_PriceTot"),  # Note el nombre diferente aquí
                accessories.get("VoltageRheostat_TSheet")
            )
        
        # ThermalWrap
        if accessories.get("ThermalWrap") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_ThermalWrap"),
                accessories.get("ThermalWrapDESC"),
                accessories.get("ThermalWrapQTYTOT"),
                accessories.get("ThermalWrap_Price"),
                accessories.get("ThermalWrap_PriceTot"),
                accessories.get("ThermalWrap_TSheet")
            )
        
        # BaseHeater
        if accessories.get("BaseHeater") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_BaseHeater"),
                accessories.get("BaseHeaterDESC"),
                accessories.get("BaseHeaterQTYTOT"),
                accessories.get("BaseHeater_Price"),
                accessories.get("BaseHeater_PriceTot"),
                accessories.get("BaseHeater_TSheet")
            )
        
        # BatterySwitch
        if accessories.get("BatterySwitch") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_BatterySwitch"),
                accessories.get("BatterySwitchDESC"),
                accessories.get("BatterySwitchQTYTOT"),
                accessories.get("BatterySwitch_Price"),
                accessories.get("BatterySwitch_PriceTot"),
                accessories.get("BatterySwitch_TSheet")
            )
        
        # BatteryHolder
        if accessories.get("BatteryHolder") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_BatteryHolder"),
                accessories.get("BatteryHolderDESC"),
                accessories.get("BatteryHolderQTYTOT"),
                accessories.get("BatteryHolder_Price"),
                accessories.get("BatteryHolder_PriceTot"),
                accessories.get("BatteryHolder_TSheet")
            )
        
        # OilHeater
        if accessories.get("OilHeater") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_OilHeater"),
                accessories.get("OilHeaterDESC"),
                accessories.get("OilHeaterQTYTOT"),
                accessories.get("OilHeater_Price"),
                accessories.get("OilHeater_PriceTot"),
                accessories.get("OilHeater_TSheet")
            )
        
        # OilLevelSwitch
        if accessories.get("OilLevelSwitch") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_OilLevelSwitch"),
                accessories.get("OilLevelSwitchDESC"),
                accessories.get("OilLevelSwitchQTYTOT"),
                accessories.get("OilLevelSwitch_Price"),
                accessories.get("OilLevelSwitch_PriceTot"),
                accessories.get("OilLevelSwitch_TSheet")
            )
        
        # CommonAlarmRelay
        if accessories.get("CommonAlarmRelay") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_CommonAlarmRelay"),
                accessories.get("CommonAlarmRelayDESC"),
                accessories.get("CommonAlarmRelayQTYTOT"),
                accessories.get("CommonAlarmRelay_Price"),
                accessories.get("CommonAlarmRel_PriceTot"),  # Note el nombre diferente aquí
                accessories.get("CommonAlarmRelay_TSheet")
            )
        
        # FunctionRelay
        if accessories.get("FunctionRelay") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_FunctionRelay"),
                accessories.get("FunctionRelayDESC"),
                accessories.get("FunctionRelayQTYTOT"),
                accessories.get("FunctionRelay_Price"),
                accessories.get("FunctionRelay_PriceTot"),
                accessories.get("FunctionRelay_TSheet")
            )
        
        # Coolant
        if accessories.get("Coolant") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_Coolant"),
                accessories.get("CoolantDESC"),
                accessories.get("CoolantQTYTOT"),
                accessories.get("Coolant_Price"),
                accessories.get("Coolant_PriceTot"),
                accessories.get("Coolant_TSheet")
            )
        
        # Oil
        if accessories.get("Oil") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_Oil"),
                accessories.get("OilDESC"),
                accessories.get("OilQTYTOT"),
                accessories.get("Oil_Price"),
                accessories.get("Oil_PriceTot"),
                accessories.get("Oil_TSheet")
            )
        
        # DisconnectSwitches
        if accessories.get("DisconnectSwitches") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_DisconnectSwitches"),
                accessories.get("DisconnectSwitchesDESC"),
                accessories.get("DisconnectSwitchesQTYTOT"),
                accessories.get("DisconnectSwitch_Price"),
                accessories.get("DisconnectSwit_PriceTot"),  # Note el nombre diferente aquí
                accessories.get("DisconnectSwitch_TSheet")
            )
        
        # EStop
        if accessories.get("EStop") not in [None, "", "Seleccione una opción", "Select an option"]:
            html += render_row(
                accessories.get("Item_AddAccesory_Estop"),
                accessories.get("EStop"),  # Usa directamente EStop como descripción
                accessories.get("EStopQTYTOT"),
                accessories.get("EStop_price"),
                accessories.get("EStop_PriceTot"),
                accessories.get("EStop_TSheet")
            )
        
        # RemoteEStop
        if accessories.get("RemoteEStop") not in [None, "", "No"]:
            html += render_row(
                accessories.get("Item_RemoteEStop"),
                accessories.get("RemoteEStopDESC"),
                accessories.get("RemoteEStopQTYTOT"),
                accessories.get("RemoteEStop_Price"),
                accessories.get("RemoteEStop_PriceTot"),
                accessories.get("RemoteEStop_TSheet")
            )
        
        # SpringIsolator
        if accessories.get("SpringIsolator") not in [None, "", "Seleccione una opción", "Select an option"]:
            html += render_row(
                accessories.get("Item_AddAccesory_Spring"),
                accessories.get("SpringIsolator"),  # Usa directamente SpringIsolator como descripción
                accessories.get("SpringIsolatorQTYTOT"),
                accessories.get("SpringIsolator_price"),
                accessories.get("SpringIsolator_PriceTot"),
                accessories.get("SpringIsolator_TSheet")
            )
        
        html += """
        </tbody>
        """
        
        return html
    
    def Get_CotizacionEnclosure_data(quote_id):

        stop_service = StopButtonEnclosureOptions_Service.StopButtonEnclosureOptionsService()

        
        

        # Obtener datos de la cotización
        quote_data = get_Definitive_quote_data(quote_id)
        if not quote_data:
            return "Error: No se encontraron datos para la cotización", 404
        
        quote_data = {k: convert_decimal(v) for k, v in quote_data.items()}
        
        #------------------------ENCLOURE-------------------------
        
        EnclosureDESC = f"{quote_data.get('EnclosureType', '')} - {quote_data.get('Enclosure_ConfigID', '')}".strip()
        EnclosureQTYTOT = quote_data['QtyGenset']

        GFCI120VDESC = '120V GFCI Receptacle'        
        GFCI120VQTYTOT = quote_data['QtyGFCI120V'] * quote_data['QtyGenset']

        Receptable120VDESC = '240V Receptacle'        
        Receptable120VQTYTOT = quote_data['QtyReceptable120V'] * quote_data['QtyGenset']

        PWCDESC = 'Prewire gen-set accesories to load center'        
        PWCQTYTOT = quote_data['QtyGenset']

        AUTLOVEDESC = 'Automatic Louvers'        
        AUTLOVEQTYTOT = quote_data['QtyGenset']

        OpeningEnclosure_Description  = 'Opening enclosure'
        OpeningEnclosure_Qtytotal = quote_data['QtyGenset']

        Item_ReceptautolouversDESC = 'Louver fail contact wired to control panel'        
        Item_ReceptautolouversQTYTOT = quote_data['QtyGenset']
    
        Enclosure_ligthACQTYTOT = quote_data['QtylightAC'] * quote_data['QtyGenset']
    
        Enclosure_ligthDCQTYTOT = quote_data['QtylightDC'] * quote_data['QtyGenset']

        Enclosure_SHeaterQTYTOT = quote_data['QtySpaceHeater'] * quote_data['QtyGenset']

        Enclosure_LCenterQTYTOT = quote_data['QtyGenset']

        OpeningEnclosure_Description='OpeningEnclousure'
        
        CotizacionEnclosure_data = {
                "quote_id": quote_id,
                "Enclosure": {
                    # Se coloca si EnclosureType es diferente de Seleccione una opcion o Select an option o Select the enclosure o Seleccione el tipo de caseta
                    "Item_Enclosuree_type": quote_data['Item_Enclosuree_type'],# ----------------------------Item Enclosuree_type
                    "EnclosureType": quote_data['EnclosureType'],
                    "EnclosureDESC": EnclosureDESC,# ----------------------------Descripción del Enclosure
                    "EnclosureQTYTOT": EnclosureQTYTOT,# ----------------------------Cantidad total del Enclosure
                    "Enclosure_price": quote_data['Enclosure_price'],# ----------------------------Precio unitario del Enclosure
                    "Enclosure_TSheet": quote_data['Enclosure_TSheet'],# ----------------------------Ficha técnica del Enclosure
                    "Enclosure_PriceTot": quote_data['Enclosure_PriceTot'],# ----------------------------Precio total del Enclosure
                    "ConfigAndAccesories_Enclosure": {
                        
                        # Se coloca si GFCI120V es diferente a No
                        "Item_GFCI120V": quote_data['Item_GFCI120V'],# ----------------------------Item GFCI120V
                        "GFCI120V": quote_data['GFCI120V'],
                        "QtyGFCI120V": quote_data['QtyGFCI120V'],
                        "GFCI120VDESC": GFCI120VDESC,# ----------------------------Descripción del GFCI120V
                        "GFCI120VQTYTOT": GFCI120VQTYTOT,# ----------------------------Cantidad total del GFCI120V
                        "GFCI120V_Price": quote_data['GFCI120V_Price'],# ----------------------------Precio unitario del GFCI120V
                        "GFCI120V_TSheet": quote_data['GFCI120V_TSheet'],# ----------------------------Ficha técnica del GFCI120V
                        "GFCI120V_PriceTot": quote_data['GFCI120V_PriceTot'],# ----------------------------Precio total del GFCI120V
                        
                        # Se coloca si Receptable120V es diferente a No
                        "Item_Receptable120V": quote_data['Item_Receptable120V'],# ----------------------------Item Receptable120V
                        "Receptable120V": quote_data['Receptable120V'],
                        "QtyReceptable120V": quote_data['QtyReceptable120V'],
                        "Receptable120VDESC": Receptable120VDESC,# ----------------------------Descripción del Receptable120V
                        "Receptable120VQTYTOT": Receptable120VQTYTOT,# ----------------------------Cantidad total del Receptable120V
                        "Receptable120V_Price": quote_data['Receptable120V_Price'],# ----------------------------Precio unitario del Receptable120V
                        "Receptable120V_TSheet": quote_data['Receptable120V_TSheet'],# ----------------------------Ficha técnica del Receptable120V
                        "Receptable120V_PriceTot": quote_data['Receptable120V_PriceTot'],# ----------------------------Precio total del Receptable120V
                        
                        # Se coloca si lightAC es diferente de Seleccione una opcion o Select an option 
                        "Item_Enclosure_ligthAC": quote_data['Item_Enclosure_ligthAC'],# ----------------------------Item del lightAC
                        "lightAC": quote_data['lightAC'],# ----------------------------Descripción del lightAC
                        "QtylightAC": quote_data['QtylightAC'],
                        "Enclosure_ligthACQTYTOT": Enclosure_ligthACQTYTOT,# ----------------------------Cantidad total del lightAC
                        "lightAC_price": quote_data['lightAC_price'],# ----------------------------Precio unitario del lightAC
                        "lightAC_TSheet": quote_data['lightAC_TSheet'],# ----------------------------Ficha técnica del lightAC
                        "lightAC_PriceTot": quote_data['lightAC_PriceTot'],# ----------------------------Precio total del lightAC
                        
                        # Se coloca si lightDC es diferente de Seleccione una opcion o Select an option 
                        "Item_Enclosure_ligthDC": quote_data['Item_Enclosure_ligthDC'],# ----------------------------Item del lightDC
                        "lightDC": quote_data['lightDC'],# ----------------------------Descripción del lightDC
                        "QtylightDC": quote_data['QtylightDC'],
                        "Enclosure_ligthDCQTYTOT": Enclosure_ligthDCQTYTOT,# ----------------------------Cantidad total del lightDC
                        "lightDC_price": quote_data['lightDC_price'],# ----------------------------Precio unitario del lightDC
                        "lightDC_TSheet": quote_data['lightDC_TSheet'],# ----------------------------Ficha técnica del lightDC
                        "lightDC_PriceTot": quote_data['lightDC_PriceTot'],# ----------------------------Precio total del lightDC
                        
                        # Se coloca si SpaceHeater es diferente de Seleccione una opcion o Select an option 
                        "Item_Enclosure_SHeater": quote_data['Item_Enclosure_SHeater'],# ----------------------------Item del SpaceHeater
                        "SpaceHeater": quote_data['SpaceHeater'],# ----------------------------Descripción del SpaceHeater
                        "QtySpaceHeater": quote_data['QtySpaceHeater'],
                        "Enclosure_SHeaterQTYTOT": Enclosure_SHeaterQTYTOT,# ----------------------------Cantidad total del SpaceHeater
                        "SpaceHeater_price": quote_data['SpaceHeater_price'],# ----------------------------Precio unitario del SpaceHeater
                        "SpaceHeater_TSheet": quote_data['SpaceHeater_TSheet'],# ----------------------------Ficha técnica del SpaceHeater
                        "SpaceHeater_PriceTot": quote_data['SpaceHeater_PriceTot'],# ----------------------------Precio total del SpaceHeater
                        
                        # Se coloca si LoadCenter es diferente de Seleccione una opcion o Select an option 
                        "Item_Enclosure_LCenter": quote_data['Item_Enclosure_LCenter'],# ----------------------------Item del LoadCenter
                        "LoadCenter": quote_data['LoadCenter'],# ----------------------------Descripción del LoadCenter
                        "Enclosure_LCenterQTYTOT": Enclosure_LCenterQTYTOT,# ----------------------------Cantidad total del LoadCenter
                        "LoadCenter_price": quote_data['LoadCenter_price'],# ----------------------------Precio unitario del LoadCenter
                        "LoadCenter_TSheet": quote_data['LoadCenter_TSheet'],# ----------------------------Ficha técnica del LoadCenter
                        "LoadCenter_PriceTot": quote_data['LoadCenter_PriceTot'],# ----------------------------Precio total del LoadCenter
                        
                        # Se coloca si PrewireAccsEnclousure es diferente a No
                        "Item_PrewireAccsEncl": quote_data['Item_PrewireAccsEncl'],# ----------------------------Item del PrewireAccsEnclousure
                        "PrewireAccsEnclousure": quote_data['PrewireAccsEnclousure'],
                        "PWCDESC": PWCDESC,# ----------------------------Descripción del PrewireAccsEnclousure
                        "PWCQTYTOT": PWCQTYTOT,# ----------------------------Cantidad total del PrewireAccsEnclousure
                        "PrewireAccsEnclo_Price": quote_data['PrewireAccsEnclo_Price'],# ----------------------------Precio unitario del PrewireAccsEnclousure
                        "PrewireAccsEnclo_TSheet": quote_data['PrewireAccsEnclo_TSheet'],# ----------------------------Ficha técnica del PrewireAccsEnclousure
                        "PrewireAccsEnc_PriceTot": quote_data['PrewireAccsEnc_PriceTot'],# ----------------------------Precio total del PrewireAccsEnclousure
                        
                        # Se coloca si autolouvers es diferente a No
                        "Item_autolouvers": quote_data['Item_autolouvers'],# ----------------------------Item del autolouvers
                        "autolouvers": quote_data['autolouvers'],
                        "AUTLOVEDESC": AUTLOVEDESC,# ----------------------------Descripción del autolouvers
                        "AUTLOVEQTYTOT": AUTLOVEQTYTOT,# ----------------------------Cantidad total del autolouvers
                        "autolouvers_Price": quote_data['autolouvers_Price'],# ----------------------------Precio unitario del autolouvers
                        "autolouvers_TSheet": quote_data['autolouvers_TSheet'],# ----------------------------Ficha técnica del autolouvers
                        "autolouvers_PriceTot": quote_data['autolouvers_PriceTot'],# ----------------------------Precio total del autolouvers
                        
                        # Se coloca si Receptautolouvers es diferente a No
                        "Item_Receptautolouvers": quote_data['Item_Receptautolouvers'],# ----------------------------Item del Receptautolouvers
                        "Receptautolouvers": quote_data['Receptautolouvers'],
                        "Item_ReceptautolouversDESC": Item_ReceptautolouversDESC,# ----------------------------Descripción del Receptautolouvers
                        "Item_ReceptautolouversQTYTOT": Item_ReceptautolouversQTYTOT,# ----------------------------Cantidad total del Receptautolouvers
                        "Receptautolouver_Price": quote_data['Receptautolouver_Price'],# ----------------------------Precio unitario del Receptautolouvers
                        "Receptautolouver_TSheet": quote_data['Receptautolouver_TSheet'],# ----------------------------Ficha técnica del Receptautolouvers
                        "Receptautolouv_PriceTot": quote_data['Receptautolouv_PriceTot'],# ----------------------------Precio total del Receptautolouvers

                        "Item_OpeningEnclousure": quote_data['Item_OpeningEnclousure'],
                        "OpeningEnclousure": quote_data['OpeningEnclousure'],
                        "OpeningEnclosure_Description": OpeningEnclosure_Description,# ----------------------------Descripción del autolouvers
                        "OpeningEnclosure_Qtytotal": OpeningEnclosure_Qtytotal,# ----------------------------Cantidad total del autolouvers
                        "OpeningEnclousure_Price": quote_data['OpeningEnclousure_Price'],
                        "OpeningEnclousure_TSheet": quote_data['OpeningEnclousure_TSheet'],
                        "OpeningEnclousure_PriceTot": quote_data['OpeningEnclousure_PriceTot'],

                        "Item_StopButtonEnclosure": quote_data['Item_StopButtonEnclosure'],
                        "StopButtonEnclosure": quote_data['StopButtonEnclosure'],
                        "StopButtonEnclosure_Qty": quote_data['StopButtonEnclosure_Qty'],# ----------------------------Cantidad total del autolouvers
                        "StopButtonEnclosure_Price": quote_data['StopButtonEnclosure_Price'],
                        "StopButtonEnclosure_TSheet": quote_data['StopButtonEnclosure_TSheet'],
                        "StopButtonEnclosure_PriceTot": quote_data['StopButtonEnclosure_PriceTot'],

                        "Item_louvers_in": quote_data['Item_louvers_in'],
                        "louvers_in" : quote_data['louvers_in'],
                        "louvers_in_price:" : quote_data['louvers_in_price'],
                        "louvers_in_tsheet" : quote_data['louvers_in_tsheet'],
                        "louvers_in_pricetot" : quote_data['louvers_in_pricetot'],

                        "Item_louvers_out": quote_data['Item_louvers_out'],
                        "louvers_out" : quote_data['louvers_out'],
                        "louvers_out_price" : quote_data['louvers_out_price'],
                        "louvers_out_tsheet" : quote_data['louvers_out_tsheet'],
                        "louvers_out_pricetot" : quote_data['louvers_out_pricetot']
                    }
                }
            }
    
        return CotizacionEnclosure_data
    def generate_quote_table_Enclosure(CotizacionEnclosure_data):
        """
        Genera el HTML para la tabla de la caseta (enclosure) con enlaces a fichas técnicas
    
        Args:
            CotizacionEnclosure_data (dict): Datos de la caseta y sus accesorios
        
        Returns:
            str: HTML para la tabla de la caseta
        """
        html = """
        <tbody>
        """
    
        # Función para renderizar una fila de la tabla con enlace a la ficha técnica
        def render_row(item, description, qty, unit_price, total_price, tech_sheet=None):
            if description is None or description == "" or description == "No":
                return ""
        
            if description in ["Seleccione una opción", "Select an option", 
                            "Select the enclosure", "Seleccione el tipo de caseta"]:
                return ""
        
            # Formatear precios
            formatted_unit_price = format_price(unit_price)
            formatted_total_price = format_price(total_price)
        
            # Si hay ficha técnica, crear un enlace, de lo contrario mostrar solo el texto
            if tech_sheet and tech_sheet.strip():
                item_cell = f'<a href="{tech_sheet}" target="_blank" class="tech-sheet-link">{item or ""}</a>'
            else:
                item_cell = item or ""
        
            return f"""
            <tr>
                <td>{item_cell}</td>
                <td>{description or ""}</td>
                <td>{qty or ""}</td>
                <td>{formatted_unit_price}</td>
                <td>{formatted_total_price}</td>
            </tr>
            """
    
        # Obtener datos de la caseta
        enclosure = CotizacionEnclosure_data.get("Enclosure", {})
        
        # Caseta principal
        if enclosure and enclosure.get("EnclosureType") not in [None, "", "Seleccione una opción", "Select an option", 
                                                            "Select the enclosure", "Seleccione el tipo de caseta"]:
            html += render_row(
                enclosure.get("Item_Enclosuree_type"),
                enclosure.get("EnclosureDESC"),
                enclosure.get("EnclosureQTYTOT"),
                enclosure.get("Enclosure_price"),
                enclosure.get("Enclosure_PriceTot"),
                enclosure.get("Enclosure_TSheet")
            )
            
            # Accesorios de la caseta
            if "ConfigAndAccesories_Enclosure" in enclosure:
                accessories = enclosure["ConfigAndAccesories_Enclosure"]
                
                # GFCI120V
                if accessories.get("GFCI120V") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_GFCI120V"),
                        accessories.get("GFCI120VDESC"),
                        accessories.get("GFCI120VQTYTOT"),
                        accessories.get("GFCI120V_Price"),
                        accessories.get("GFCI120V_PriceTot"),
                        accessories.get("GFCI120V_TSheet")
                    )
                
                # Receptable120V
                if accessories.get("Receptable120V") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Receptable120V"),
                        accessories.get("Receptable120VDESC"),
                        accessories.get("Receptable120VQTYTOT"),
                        accessories.get("Receptable120V_Price"),
                        accessories.get("Receptable120V_PriceTot"),
                        accessories.get("Receptable120V_TSheet")
                    )
                
                # lightAC
                if accessories.get("lightAC") not in [None, "", "Seleccione una opción", "Select an option"]:
                    html += render_row(
                        accessories.get("Item_Enclosure_ligthAC"),
                        accessories.get("lightAC"),
                        accessories.get("Enclosure_ligthACQTYTOT"),
                        accessories.get("lightAC_price"),
                        accessories.get("lightAC_PriceTot"),
                        accessories.get("lightAC_TSheet")
                    )
                
                # lightDC
                if accessories.get("lightDC") not in [None, "", "Seleccione una opción", "Select an option"]:
                    html += render_row(
                        accessories.get("Item_Enclosure_ligthDC"),
                        accessories.get("lightDC"),
                        accessories.get("Enclosure_ligthDCQTYTOT"),
                        accessories.get("lightDC_price"),
                        accessories.get("lightDC_PriceTot"),
                        accessories.get("lightDC_TSheet")
                    )
                
                # SpaceHeater
                if accessories.get("SpaceHeater") not in [None, "", "Seleccione una opción", "Select an option"]:
                    html += render_row(
                        accessories.get("Item_Enclosure_SHeater"),
                        accessories.get("SpaceHeater"),
                        accessories.get("Enclosure_SHeaterQTYTOT"),
                        accessories.get("SpaceHeater_price"),
                        accessories.get("SpaceHeater_PriceTot"),
                        accessories.get("SpaceHeater_TSheet")
                    )
                
                # LoadCenter
                if accessories.get("LoadCenter") not in [None, "", "Seleccione una opción", "Select an option"]:
                    html += render_row(
                        accessories.get("Item_Enclosure_LCenter"),
                        accessories.get("LoadCenter"),
                        accessories.get("Enclosure_LCenterQTYTOT"),
                        accessories.get("LoadCenter_price"),
                        accessories.get("LoadCenter_PriceTot"),
                        accessories.get("LoadCenter_TSheet")
                    )
                
                # PrewireAccsEnclousure
                if accessories.get("PrewireAccsEnclousure") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_PrewireAccsEncl"),
                        accessories.get("PWCDESC"),
                        accessories.get("PWCQTYTOT"),
                        accessories.get("PrewireAccsEnclo_Price"),
                        accessories.get("PrewireAccsEnc_PriceTot"),  # Note el nombre diferente aquí
                        accessories.get("PrewireAccsEnclo_TSheet")
                    )
                
                # Apertura interna
                if accessories.get("OpeningEnclousure") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_OpeningEnclousure"),
                        accessories.get("OpeningEnclosure_Description"),
                        accessories.get("OpeningEnclosure_Qtytotal"),
                        accessories.get("OpeningEnclousure_Price"),
                        accessories.get("OpeningEnclousure_PriceTot"),
                        accessories.get("OpeningEnclousure_TSheet")
                )
                    
                
                # StopButtonEnclosure
                if accessories.get("StopButtonEnclosure") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_StopButtonEnclosure"),
                        accessories.get("StopButtonEnclosure"),
                        accessories.get("StopButtonEnclosure_Qty"),
                        accessories.get("StopButtonEnclosure_Price"),
                        accessories.get("StopButtonEnclosure_PriceTot"),
                        accessories.get("StopButtonEnclosure_TSheet")
                    )

                
                # autolouvers
                if accessories.get("autolouvers") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_autolouvers"),
                        accessories.get("AUTLOVEDESC"),
                        accessories.get("AUTLOVEQTYTOT"),
                        accessories.get("autolouvers_Price"),
                        accessories.get("autolouvers_PriceTot"),
                        accessories.get("autolouvers_TSheet")
                    )
                
                # Receptautolouvers
                if accessories.get("Receptautolouvers") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_Receptautolouvers"),
                        accessories.get("Item_ReceptautolouversDESC"),
                        accessories.get("Item_ReceptautolouversQTYTOT"),
                        accessories.get("Receptautolouver_Price"),
                        accessories.get("Receptautolouv_PriceTot"),  # Note el nombre diferente aquí
                        accessories.get("Receptautolouver_TSheet")
                    )

                if accessories.get("louvers_in") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_louvers_in"),
                        accessories.get("louvers_in"),
                        "1",
                        accessories.get("louvers_in_price"),
                        accessories.get("louvers_in_pricetot"),  
                        accessories.get("louvers_in_tsheet")
                    )
                
                if accessories.get("louvers_out") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_louvers_out"),
                        accessories.get("louvers_out"),
                        "1",
                        accessories.get("louvers_out_price"),
                        accessories.get("louvers_out_pricetot"),  
                        accessories.get("louvers_out_tsheet")
                    )
        
        html += """
        </tbody>
        """
        
        return html
    
    def Get_CotizacionTank_data(quote_id):
        # Obtener datos de la cotización
        quote_data = get_Definitive_quote_data(quote_id)
        if not quote_data:
            return "Error: No se encontraron datos para la cotización", 404
        
        quote_data = {k: convert_decimal(v) for k, v in quote_data.items()}
        
        #------------------------TANK-------------------------

        TankDESC = f"{quote_data.get('TankCapacity', '')} - {quote_data.get('TankType', '')} - {quote_data.get('Tank_CapacityGAL', '')} gal".strip()
        TankQTYTOT = quote_data['QtyGenset']

        BreakTraySwitchDESC = 'Rupture basin switch'
        BreakTraySwitchQTYTOT = quote_data['QtyGenset']

        FuelLevelSensorDESC = 'Fuel level sensor'
        FuelLevelSensorQTYTOT = quote_data['QtyGenset']

        OverfillValveDESC = 'Overfill protection valve'
        OverfillValveQTYTOT = quote_data['QtyGenset']

        DualFuelSwitchDESC = 'Dual fuel switches'
        DualFuelSwitchQTYTOT = quote_data['QtyGenset']
        
        HighFuelSwitchDESC = 'High fuel level switch (FDEP)'
        HighFuelSwitchQTYTOT = quote_data['QtyGenset']

        RemoteAlarmPDESC = 'Remote Alarm Panel'
        RemoteAlarmPQTYTOT = quote_data['QtyGenset']

        VentPipeDESC = '12 Ft above grade (extended vent piping)'
        VentPipeQTYTOT = quote_data['QtyGenset']

        FlammableLDESC = 'Combustible liquids- Keep fire away (qty.2)'
        FlammableLQTYTOT = quote_data['QtyGenset']

        NFPAIdentificatDESC = 'NFPA 7044 identification (qty 2)'
        NFPAIdentificatQTYTOT = quote_data['QtyGenset']

        NoSmokingDESC = 'No Smoking (qty 2)'
        NoSmokingQTYTOT = quote_data['QtyGenset']

        TankNumberDESC = 'TTank number and safe fill height (qty.2)'
        TankNumberQTYTOT = quote_data['QtyGenset']

        FluidContainmentDESC = '100% Engine containment'
        FluidContainmentQTYTOT = quote_data['QtyGenset']

        Tank_SpillContQTYTOT = quote_data['QtyGenset']
        
        CotizacionTank_data = {
                "quote_id": quote_id,
                "Tank": {
                    # Se coloca si TankType es diferente de Seleccione una opcion o Select an option o Seleccionela capacidad del tanque o Select the base tank
                    "TankType": quote_data['TankType'],
                    "Tank_ConfigID": quote_data['Tank_ConfigID'],# ----------------------------Item del Tank
                    "TankDESC" : TankDESC,# ----------------------------Descripción del Tank
                    "TankQTYTOT" : TankQTYTOT,# ----------------------------Cantidad total del Tank
                    "Tank_price": quote_data['Tank_price'],# ----------------------------Precio unitario del Tank
                    "Tank_TSheet": quote_data['Tank_TSheet'],# ----------------------------Ficha técnica del Tank
                    "Tank_PriceTot": quote_data['Tank_PriceTot'],# ----------------------------Precio total del Tank
                    "ConfigAndAccesories_Tank": {
                        # Se coloca si BreakTraySwitch es diferente a No
                        "Item_BreakTraySwitch": quote_data['Item_BreakTraySwitch'],# ----------------------------Item del BreakTraySwitch
                        "BreakTraySwitch": quote_data['BreakTraySwitch'],
                        "BreakTraySwitchDESC": BreakTraySwitchDESC,# ----------------------------Descripción del BreakTraySwitch
                        "BreakTraySwitchQTYTOT": BreakTraySwitchQTYTOT,# ----------------------------Cantidad total del BreakTraySwitch
                        "BreakTraySwitch_Price": quote_data['BreakTraySwitch_Price'],# ----------------------------Precio unitario del BreakTraySwitch
                        "BreakTraySwitch_TSheet": quote_data['BreakTraySwitch_TSheet'],# ----------------------------Ficha técnica del BreakTraySwitch
                        "BreakTraySwitc_PriceTot": quote_data['BreakTraySwitc_PriceTot'],# ----------------------------Precio total del BreakTraySwitch

                        # Se coloca si FuelLevelSensor es diferente a No
                        "Item_FuelLevelSensor": quote_data['Item_FuelLevelSensor'],# ----------------------------Item del FuelLevelSensor
                        "FuelLevelSensor": quote_data['FuelLevelSensor'],
                        "FuelLevelSensorDESC": FuelLevelSensorDESC,# ----------------------------Descripción del FuelLevelSensor
                        "FuelLevelSensorQTYTOT": FuelLevelSensorQTYTOT,# ----------------------------Cantidad total del FuelLevelSensor
                        "FuelLevelSensor_Price": quote_data['FuelLevelSensor_Price'],# ----------------------------Precio unitario del FuelLevelSensor
                        "FuelLevelSensor_TSheet": quote_data['FuelLevelSensor_TSheet'],# ----------------------------Ficha técnica del FuelLevelSensor
                        "FuelLevelSenso_PriceTot": quote_data['FuelLevelSenso_PriceTot'],# ----------------------------Precio total del FuelLevelSensor

                        # Se coloca si SpillContainment es diferente de Seleccione una opcion o Select an option 
                        "Item_Tank_SpillCont": quote_data['Item_Tank_SpillCont'],# ----------------------------Item del SpillContainment
                        "SpillContainment": quote_data['SpillContainment'],# ----------------------------Descripción del SpillContainment
                        "Tank_SpillContQTYTOT": Tank_SpillContQTYTOT,# ----------------------------Cantidad total del SpillContainment
                        "SpillContainment_Price": quote_data['SpillContainment_Price'],# ----------------------------Precio unitario del SpillContainment
                        "SpillContainment_TSheet": quote_data['SpillContainment_TSheet'],# ----------------------------Ficha técnica del SpillContainment
                        "SpillContainme_PriceTot": quote_data['SpillContainme_PriceTot'],# ----------------------------Precio total del SpillContainment

                        # Se coloca si OverfillValve es diferente a No
                        "Item_OverfillValve": quote_data['Item_OverfillValve'],# ----------------------------Item del OverfillValve
                        "OverfillValve": quote_data['OverfillValve'],
                        "OverfillValveDESC" :OverfillValveDESC,# ----------------------------Descripción del OverfillValve
                        "OverfillValveQTYTOT": OverfillValveQTYTOT,# ----------------------------Cantidad total del OverfillValve
                        "OverfillValve_Price": quote_data['OverfillValve_Price'],# ----------------------------Precio unitario del OverfillValve
                        "OverfillValve_TSheet": quote_data['OverfillValve_TSheet'],# ----------------------------Ficha técnica del OverfillValve
                        "OverfillValve_PriceTot": quote_data['OverfillValve_PriceTot'],# ----------------------------Precio total del OverfillValve

                        # Se coloca si DualFuelSwitches es diferente a No
                        "Item_DualFuelSwitch": quote_data['Item_DualFuelSwitch'],# ----------------------------Item del DualFuelSwitches
                        "DualFuelSwitches": quote_data['DualFuelSwitches'],
                        "DualFuelSwitchDESC": DualFuelSwitchDESC,# ----------------------------Descripción del DualFuelSwitches
                        "DualFuelSwitchQTYTOT": DualFuelSwitchQTYTOT,# ----------------------------Cantidad total del DualFuelSwitches
                        "DualFuelSwitches_Price": quote_data['DualFuelSwitches_Price'],# ----------------------------Precio unitario del DualFuelSwitches
                        "DualFuelSwitches_TSheet": quote_data['DualFuelSwitches_TSheet'],# ----------------------------Ficha técnica del DualFuelSwitches
                        "DualFuelSwitch_PriceTot": quote_data['DualFuelSwitch_PriceTot'],# ----------------------------Precio total del DualFuelSwitches

                        # Se coloca si HighFuelSwitch es diferente a No
                        "Item_HighFuelSwitch": quote_data['Item_HighFuelSwitch'],# ----------------------------Item del HighFuelSwitch
                        "HighFuelSwitch": quote_data['HighFuelSwitch'],
                        "HighFuelSwitchDESC": HighFuelSwitchDESC,# ----------------------------Descripción del HighFuelSwitch
                        "HighFuelSwitchQTYTOT": HighFuelSwitchQTYTOT,# ----------------------------Cantidad total del HighFuelSwitch
                        "HighFuelSwitch_Price": quote_data['HighFuelSwitch_Price'],# ----------------------------Precio unitario del HighFuelSwitch
                        "HighFuelSwitch_TSheet": quote_data['HighFuelSwitch_TSheet'],# ----------------------------Ficha técnica del HighFuelSwitch
                        "HighFuelSwitch_PriceTot": quote_data['HighFuelSwitch_PriceTot'],# ----------------------------Precio total del HighFuelSwitch

                        # Se coloca si RemoteAlarmPanel es diferente a No
                        "Item_RemoteAlarmP": quote_data['Item_RemoteAlarmP'],# ----------------------------Item del RemoteAlarmPanel
                        "RemoteAlarmPanel": quote_data['RemoteAlarmPanel'],
                        "RemoteAlarmPDESC": RemoteAlarmPDESC,# ----------------------------Descripción del RemoteAlarmPanel
                        "RemoteAlarmPQTYTOT": RemoteAlarmPQTYTOT,# ----------------------------Cantidad total del RemoteAlarmPanel
                        "RemoteAlarmPanel_Price": quote_data['RemoteAlarmPanel_Price'],# ----------------------------Precio unitario del RemoteAlarmPanel
                        "RemoteAlarmPanel_TSheet": quote_data['RemoteAlarmPanel_TSheet'],# ----------------------------Ficha técnica del RemoteAlarmPanel
                        "RemoteAlarmPan_PriceTot": quote_data['RemoteAlarmPan_PriceTot'],# ----------------------------Precio total del RemoteAlarmPanel

                        # Se coloca si VentPipe es diferente a No
                        "Item_VentPipe": quote_data['Item_VentPipe'],# ----------------------------Item del VentPipe
                        "VentPipe": quote_data['VentPipe'],
                        "VentPipeDESC": VentPipeDESC,# ----------------------------Descripción del VentPipe
                        "VentPipeQTYTOT": VentPipeQTYTOT,# ----------------------------Cantidad total del VentPipe
                        "VentPipe_Price": quote_data['VentPipe_Price'],# ----------------------------Precio unitario del VentPipe
                        "VentPipe_TSheet": quote_data['VentPipe_TSheet'],# ----------------------------Ficha técnica del VentPipe
                        "VentPipe_PriceTot": quote_data['VentPipe_PriceTot'],# ----------------------------Precio total del VentPipe

                        # Se coloca si FlammableLiquids es diferente a No
                        "Item_FlammableL": quote_data['Item_FlammableL'],# ----------------------------Item del FlammableLiquids
                        "FlammableLiquids": quote_data['FlammableLiquids'],
                        "FlammableLDESC": FlammableLDESC,# ----------------------------Descripción del FlammableLiquids
                        "FlammableLQTYTOT": FlammableLQTYTOT,# ----------------------------Cantidad total del FlammableLiquids
                        "FlammableLiquids_Price": quote_data['FlammableLiquids_Price'],# ----------------------------Precio unitario del FlammableLiquids
                        "FlammableLiquids_TSheet": quote_data['FlammableLiquids_TSheet'],# ----------------------------Ficha técnica del FlammableLiquids
                        "FlammableLiqui_PriceTot": quote_data['FlammableLiqui_PriceTot'],# ----------------------------Precio total del FlammableLiquids

                        # Se coloca si NFPAIdentification es diferente a No
                        "Item_NFPAIdentificat": quote_data['Item_NFPAIdentificat'],# ----------------------------Item del NFPAIdentification
                        "NFPAIdentification": quote_data['NFPAIdentification'],
                        "NFPAIdentificatDESC": NFPAIdentificatDESC,# ----------------------------Descripción del NFPAIdentification
                        "NFPAIdentificatQTYTOT": NFPAIdentificatQTYTOT,# ----------------------------Cantidad total del NFPAIdentification
                        "NFPAIdentificat_Price": quote_data['NFPAIdentificat_Price'],# ----------------------------Precio unitario del NFPAIdentification
                        "NFPAIdentificat_TSheet": quote_data['NFPAIdentificat_TSheet'],# ----------------------------Ficha técnica del NFPAIdentification
                        "NFPAIdentifica_PriceTot": quote_data['NFPAIdentifica_PriceTot'],# ----------------------------Precio total del NFPAIdentification

                        # Se coloca si NoSmoking es diferente a No
                        "Item_NoSmoking": quote_data['Item_NoSmoking'],# ----------------------------Item del NoSmoking
                        "NoSmoking": quote_data['NoSmoking'],
                        "NoSmokingDESC":NoSmokingDESC,# ----------------------------Descripción del NoSmoking
                        "NoSmokingQTYTOT":NoSmokingQTYTOT,# ----------------------------Cantidad total del NoSmoking
                        "NoSmoking_Price": quote_data['NoSmoking_Price'],# ----------------------------Precio unitario del NoSmoking
                        "NoSmoking_TSheet": quote_data['NoSmoking_TSheet'],# ----------------------------Ficha técnica del NoSmoking
                        "NoSmoking_PriceTot": quote_data['NoSmoking_PriceTot'],# ----------------------------Precio total del NoSmoking

                        # Se coloca si TankNumber es diferente a No
                        "Item_TankNumber": quote_data['Item_TankNumber'],# ----------------------------Item del TankNumber
                        "TankNumber": quote_data['TankNumber'],
                        "TankNumberDESC": TankNumberDESC,# ----------------------------Descripción del TankNumber
                        "TankNumberQTYTOT": TankNumberQTYTOT,# ----------------------------Cantidad total del TankNumber
                        "TankNumber_Price": quote_data['TankNumber_Price'],# ----------------------------Precio unitario del TankNumber
                        "TankNumber_TSheet": quote_data['TankNumber_TSheet'],# ----------------------------Ficha técnica del TankNumber
                        "TankNumber_PriceTot": quote_data['TankNumber_PriceTot'],# ----------------------------Precio total del TankNumber

                        # Se coloca si FluidContainment es diferente a No
                        "Item_FluidContainment": quote_data['Item_FluidContainment'],# ----------------------------Item del FluidContainment
                        "FluidContainment": quote_data['FluidContainment'],
                        "FluidContainmentDESC": FluidContainmentDESC,# ----------------------------Descripción del FluidContainment
                        "FluidContainmentQTYTOT": FluidContainmentQTYTOT,# ----------------------------Cantidad total del FluidContainment
                        "FluidContainment_Price": quote_data['FluidContainment_Price'],# ----------------------------Precio unitario del FluidContainment
                        "FluidContainment_TSheet": quote_data['FluidContainment_TSheet'],# ----------------------------Ficha técnica del FluidContainment
                        "FluidContainme_PriceTot": quote_data['FluidContainme_PriceTot']# ----------------------------Precio total del FluidContainment
                    }
                }
            }

        return CotizacionTank_data
    def generate_quote_table_Tank(CotizacionTank_data):
        """
        Genera el HTML para la tabla del tanque de combustible con enlaces a fichas técnicas
    
        Args:
            CotizacionTank_data (dict): Datos del tanque y sus accesorios
        
        Returns:
            str: HTML para la tabla del tanque
        """
        html = """
        <tbody>
        """
    
        # Función para renderizar una fila de la tabla con enlace a la ficha técnica
        def render_row(item, description, qty, unit_price, total_price, tech_sheet=None):
            if description is None or description == "" or description == "No":
                return ""
        
            if description in ["Seleccione una opción", "Select an option", 
                            "Seleccionela capacidad del tanque", "Select the base tank"]:
                return ""
        
            # Formatear precios
            formatted_unit_price = format_price(unit_price)
            formatted_total_price = format_price(total_price)
        
            # Si hay ficha técnica, crear un enlace, de lo contrario mostrar solo el texto
            if tech_sheet and tech_sheet.strip():
                item_cell = f'<a href="{tech_sheet}" target="_blank" class="tech-sheet-link">{item or ""}</a>'
            else:
                item_cell = item or ""
        
            return f"""
            <tr>
                <td>{item_cell}</td>
                <td>{description or ""}</td>
                <td>{qty or ""}</td>
                <td>{formatted_unit_price}</td>
                <td>{formatted_total_price}</td>
            </tr>
            """
    
        # Obtener datos del tanque
        tank = CotizacionTank_data.get("Tank", {})
        
        # Tanque principal
        if tank and tank.get("TankType") not in [None, "", "Seleccione una opción", "Select an option", 
                                            "Seleccione la capacidad del tanque", "Select the base tank"]:
            html += render_row(
                tank.get("Tank_ConfigID"),
                tank.get("TankDESC"),
                tank.get("TankQTYTOT"),
                tank.get("Tank_price"),
                tank.get("Tank_PriceTot"),
                tank.get("Tank_TSheet")
            )
            
            # Accesorios del tanque
            if "ConfigAndAccesories_Tank" in tank:
                accessories = tank["ConfigAndAccesories_Tank"]
                
                # BreakTraySwitch
                if accessories.get("BreakTraySwitch") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_BreakTraySwitch"),
                        accessories.get("BreakTraySwitchDESC"),
                        accessories.get("BreakTraySwitchQTYTOT"),
                        accessories.get("BreakTraySwitch_Price"),
                        accessories.get("BreakTraySwitc_PriceTot"),  # Note el nombre diferente aquí
                        accessories.get("BreakTraySwitch_TSheet")
                    )
                
                # FuelLevelSensor
                if accessories.get("FuelLevelSensor") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_FuelLevelSensor"),
                        accessories.get("FuelLevelSensorDESC"),
                        accessories.get("FuelLevelSensorQTYTOT"),
                        accessories.get("FuelLevelSensor_Price"),
                        accessories.get("FuelLevelSenso_PriceTot"),  # Note el nombre diferente aquí
                        accessories.get("FuelLevelSensor_TSheet")
                    )
                
                # SpillContainment
                if accessories.get("SpillContainment") not in [None, "", "Seleccione una opción", "Select an option"]:
                    html += render_row(
                        accessories.get("Item_Tank_SpillCont"),
                        accessories.get("SpillContainment"),
                        accessories.get("Tank_SpillContQTYTOT"),
                        accessories.get("SpillContainment_Price"),
                        accessories.get("SpillContainme_PriceTot"),  # Note el nombre diferente aquí
                        accessories.get("SpillContainment_TSheet")
                    )
                
                # OverfillValve
                if accessories.get("OverfillValve") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_OverfillValve"),
                        accessories.get("OverfillValveDESC"),
                        accessories.get("OverfillValveQTYTOT"),
                        accessories.get("OverfillValve_Price"),
                        accessories.get("OverfillValve_PriceTot"),
                        accessories.get("OverfillValve_TSheet")
                    )
                
                # DualFuelSwitches
                if accessories.get("DualFuelSwitches") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_DualFuelSwitch"),
                        accessories.get("DualFuelSwitchDESC"),
                        accessories.get("DualFuelSwitchQTYTOT"),
                        accessories.get("DualFuelSwitches_Price"),
                        accessories.get("DualFuelSwitch_PriceTot"),  # Note el nombre diferente aquí
                        accessories.get("DualFuelSwitches_TSheet")
                    )
                
                # HighFuelSwitch
                if accessories.get("HighFuelSwitch") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_HighFuelSwitch"),
                        accessories.get("HighFuelSwitchDESC"),
                        accessories.get("HighFuelSwitchQTYTOT"),
                        accessories.get("HighFuelSwitch_Price"),
                        accessories.get("HighFuelSwitch_PriceTot"),
                        accessories.get("HighFuelSwitch_TSheet")
                    )
                
                # RemoteAlarmPanel
                if accessories.get("RemoteAlarmPanel") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_RemoteAlarmP"),
                        accessories.get("RemoteAlarmPDESC"),
                        accessories.get("RemoteAlarmPQTYTOT"),
                        accessories.get("RemoteAlarmPanel_Price"),
                        accessories.get("RemoteAlarmPan_PriceTot"),  # Note el nombre diferente aquí
                        accessories.get("RemoteAlarmPanel_TSheet")
                    )
                
                # VentPipe
                if accessories.get("VentPipe") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_VentPipe"),
                        accessories.get("VentPipeDESC"),
                        accessories.get("VentPipeQTYTOT"),
                        accessories.get("VentPipe_Price"),
                        accessories.get("VentPipe_PriceTot"),
                        accessories.get("VentPipe_TSheet")
                    )
                
                # FlammableLiquids
                if accessories.get("FlammableLiquids") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_FlammableL"),
                        accessories.get("FlammableLDESC"),
                        accessories.get("FlammableLQTYTOT"),
                        accessories.get("FlammableLiquids_Price"),
                        accessories.get("FlammableLiqui_PriceTot"),  # Note el nombre diferente aquí
                        accessories.get("FlammableLiquids_TSheet")
                    )
                
                # NFPAIdentification
                if accessories.get("NFPAIdentification") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_NFPAIdentificat"),
                        accessories.get("NFPAIdentificatDESC"),
                        accessories.get("NFPAIdentificatQTYTOT"),
                        accessories.get("NFPAIdentificat_Price"),
                        accessories.get("NFPAIdentifica_PriceTot"),  # Note el nombre diferente aquí
                        accessories.get("NFPAIdentificat_TSheet")
                    )
                
                # NoSmoking
                if accessories.get("NoSmoking") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_NoSmoking"),
                        accessories.get("NoSmokingDESC"),
                        accessories.get("NoSmokingQTYTOT"),
                        accessories.get("NoSmoking_Price"),
                        accessories.get("NoSmoking_PriceTot"),
                        accessories.get("NoSmoking_TSheet")
                    )
                
                # TankNumber
                if accessories.get("TankNumber") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_TankNumber"),
                        accessories.get("TankNumberDESC"),
                        accessories.get("TankNumberQTYTOT"),
                        accessories.get("TankNumber_Price"),
                        accessories.get("TankNumber_PriceTot"),
                        accessories.get("TankNumber_TSheet")
                    )
                
                # FluidContainment
                if accessories.get("FluidContainment") not in [None, "", "No"]:
                    html += render_row(
                        accessories.get("Item_FluidContainment"),
                        accessories.get("FluidContainmentDESC"),
                        accessories.get("FluidContainmentQTYTOT"),
                        accessories.get("FluidContainment_Price"),
                        accessories.get("FluidContainme_PriceTot"),  # Note el nombre diferente aquí
                        accessories.get("FluidContainment_TSheet")
                    )
        
        html += """
        </tbody>
        """
        
        return html

    def Get_warranty_and_testing_pricing(quote_id, Genset_price):
        """
        Agrega información de garantías y pruebas a la cotización.
        """
        
        # Obtener datos de la cotización
        quote_data = get_Definitive_quote_data(quote_id)
        if not quote_data:
            return "Error: No se encontraron datos para la cotización", 404
        
        quote_data = {k: convert_decimal(v) for k, v in quote_data.items()}

        Garanty_Percentage = float(quote_data['Garanty_Percentage']) if isinstance(quote_data['Garanty_Percentage'], str) else quote_data['Garanty_Percentage']
        
        GarantyQTYTOT = quote_data['QtyGenset']
        unitaryprice_genset = Genset_price / GarantyQTYTOT
        
        Garanty_price = unitaryprice_genset * Garanty_Percentage
        
        Garanty_PriceTot = unitaryprice_genset * Garanty_Percentage * GarantyQTYTOT
        
        TestingQTYTOT = quote_data['QtyGenset']
        
        CotizacionWarrantyAndTest_data = {
                "quote_id": quote_id,       
                "Warranty": {
                    "Item_PrjWar_Warranty": quote_data['Item_PrjWar_Warranty'], # ----------------------------Item de la garantía
                    "Garanty": quote_data['Garanty'], # ----------------------------Descripción de la garantía
                    "GarantyQTYTOT": GarantyQTYTOT, # ----------------------------Cantidad total de la garantía
                    "Garanty_Percentage": quote_data['Garanty_Percentage'],
                    "Garanty_priceTAB": quote_data['Garanty_price'],
                    "Garanty_price": Garanty_price, # ----------------------------Precio unitario de la garantía
                    "Garanty_PriceTotTAB": quote_data['Garanty_PriceTot'],
                    "Garanty_PriceTot": Garanty_PriceTot # ----------------------------Precio total de la garantía
                },
                "Testing": {
                    "Item_PrjWar_Testing": quote_data['Item_PrjWar_Testing'], # ----------------------------Item de las pruebas
                    "Teasting": quote_data['Teasting'], # ----------------------------Descripción de las pruebas
                    "Teasting_ConfigID": quote_data['Teasting_ConfigID'],
                    "TestingQTYTOT" : TestingQTYTOT, # ----------------------------Cantidad total de las pruebas
                    "Teasting_price": quote_data['Teasting_price'],# ----------------------------Precio unitario de las pruebas
                    "Teasting_Document": quote_data['Teasting_Document'],
                    "Teasting_PriceTot": quote_data['Teasting_PriceTot']# ----------------------------Precio total de las pruebas
                },
                "PriceWarrantyAndTest": Garanty_PriceTot + quote_data['Teasting_PriceTot']
            }        
        
        return CotizacionWarrantyAndTest_data

    def get_country_discont(quote_id, GranTotal):
        """
        Retorna el valor del descuento
        """

        #Obtener datos de la cotización
        quote_data = get_Definitive_quote_data(quote_id)
        if not quote_data:
            return "Error: No se encontraron datos para al cotización", 404
        
        # Obtener datos de los descuentos en base al QuoteID
        country_discount_data =  get_discount_country_value(quote_id)

        # Se crea diccionario con los datos de la tabla paises
        rCountryData = {
            "isoCode": country_discount_data[1],
            "state": country_discount_data[2],
            "isDiscount": country_discount_data[3],
            "descuento": country_discount_data[4]
        }
       
       # Variable para almacenar el total calculado (gran total +- el valor del descuento)
        total = 0

        if  rCountryData['descuento'] > Decimal('0'):
            granTotalDecimal = Decimal(str(GranTotal))
            # Se calcula el valor del porcentaje que se va sumar o resta del gran total
            descuento  = rCountryData['descuento'] * granTotalDecimal

            # Si isDiscount = 1 entonces hay descuento.
            if rCountryData['isDiscount'] == True:
                total  =  granTotalDecimal - descuento
            # Sino es el caso, entonces es un cargo.
            else:
                total = granTotalDecimal + descuento
            
            # Se crea diccionario con el total calculado, el valor del descuento y la bandera del descuento.
            payload = {
                "total": total,
                "discount": rCountryData['descuento'],
                "isDiscount" : rCountryData['isDiscount']
            }
        else:
            payload = {
                "total": total
            }


        return payload

    def generate_quote_table_WT(CotizacionWarrantyAndTest_data):
        """
        Genera el HTML para la tabla de garantía y pruebas con enlaces a fichas técnicas
    
        Args:
            CotizacionWarrantyAndTest_data (dict): Datos de garantía y pruebas
        
        Returns:
            str: HTML para la tabla de garantía y pruebas
        """
        html = """
        <tbody>
        """
    
        # Función para renderizar una fila de la tabla con enlace a la ficha técnica
        def render_row(item, description, qty, unit_price, total_price, tech_sheet=None):
            if description is None or description == "":
                return ""
        
            # Formatear precios
            formatted_unit_price = format_price(unit_price)
            formatted_total_price = format_price(total_price)
        
            # Si hay ficha técnica, crear un enlace, de lo contrario mostrar solo el texto
            if tech_sheet and tech_sheet.strip():
                item_cell = f'<a href="{tech_sheet}" target="_blank" class="tech-sheet-link">{item or ""}</a>'
            else:
                item_cell = item or ""
        
            return f"""
            <tr>
                <td>{item_cell}</td>
                <td>{description or ""}</td>
                <td>{qty or ""}</td>
                <td>{formatted_unit_price}</td>
                <td>{formatted_total_price}</td>
            </tr>
            """
    
        # Obtener datos de garantía
        warranty = CotizacionWarrantyAndTest_data.get("Warranty", {})
        
        # Generar fila para la garantía
        if warranty and warranty.get("Garanty"):
            html += render_row(
                warranty.get("Item_PrjWar_Warranty"),
                warranty.get("Garanty"),
                warranty.get("GarantyQTYTOT"),
                warranty.get("Garanty_price"),
                warranty.get("Garanty_PriceTot"),
                None  # No hay ficha técnica para la garantía en el modelo de datos
            )
        
        # Obtener datos de pruebas
        testing = CotizacionWarrantyAndTest_data.get("Testing", {})
        
        # Generar fila para las pruebas
        if testing and testing.get("Teasting"):
            html += render_row(
                testing.get("Item_PrjWar_Testing"),
                testing.get("Teasting"),
                testing.get("TestingQTYTOT"),
                testing.get("Teasting_price"),
                testing.get("Teasting_PriceTot"),
                testing.get("Teasting_Document")  # Documento de pruebas como ficha técnica
            )
        
        html += """
        </tbody>
        """
        
        return html
    
    def sum_total_prices(html_table):
        """
        Suma todos los importes totales de una tabla HTML.
        
        Args:
            html_table (str): HTML de la tabla generada
            
        Returns:
            float: La suma total de todos los importes
        """
        import re
        
        total_sum = 0.0
        
        # Buscar todos los valores en la última columna (formatted_total_price)
        # Esto busca el contenido entre <td> y </td> en la última columna de cada fila
        pattern = r'<tr>.*?<td>.*?</td>.*?<td>.*?</td>.*?<td>.*?</td>.*?<td>.*?</td>.*?<td>(.*?)</td>.*?</tr>'
        
        # Buscar todas las coincidencias en el HTML
        matches = re.findall(pattern, html_table, re.DOTALL)
        
        for formatted_price in matches:
            # Eliminar cualquier espacio en blanco, símbolos de moneda, etc.
            # y conservar solo dígitos y el punto decimal
            clean_price = ''.join(c for c in formatted_price if c.isdigit() or c == '.')
            
            # Convertir a float y sumar al total
            try:
                if clean_price:  # Verificar que no esté vacío
                    price_value = float(clean_price)
                    total_sum += price_value
            except ValueError:
                # Si hay algún error en la conversión, continuar
                continue
        
        return total_sum
    
    def format_price(price):
        """
        Formatea un precio a formato de moneda (USD)
        
        Args:
            price (float): Precio a formatear
            
        Returns:
            str: Precio formateado
        """
        if price is None:
            return "$0.00"
        
        try:
            return "${:,.2f}".format(float(price))
        except (TypeError, ValueError):
            return "$0.00"
    
    def convert_decimal(obj):
        """Convierte objetos Decimal a float para serialización JSON"""
        if isinstance(obj, Decimal):
            return float(obj)
        return obj
    
    @app.route('/Ventas/VentasEUA/generar_pdf/<quote_id>', methods=['POST'])
    def generar_pdf_cotizador(quote_id):
        try:
            # Verificar que el quote_id sea válido
            if not quote_id:
                return jsonify({
                    'status': 'error',
                    'message': 'ID de cotización no válido'
                }), 400
            # Guardar el quote_id en sesión (si no está ya)
            session['quote_id'] = quote_id
            # Generar un token único para esta solicitud
            token = str(uuid.uuid4())
            
            # Construir la URL completa del cotizador
            base_url = request.host_url.rstrip('/')
            quote_url = f"{base_url}/Ventas/VentasEUA/VEUcotizadorbase?quote_id={quote_id}"
            
            base_dir = current_app.root_path #como estamos trabajando asi obtenemos la direccion del app.py
            
            # Ruta donde se guardará el PDF temporalmente
            output_dir = os.path.join(base_dir, "static", "pdf", "Ventas", "VentasEUA")
            os.makedirs(output_dir, exist_ok=True)
            output_path = os.path.join(output_dir, f"cotizacion_{token}.pdf")
            
            # Construir la ruta completa al script de Puppeteer
            script_path = os.path.join(
                base_dir, "puppeteer_pdf", "Ventas", "VentasEUA", "VEUcotizador.js"
            )
            
            # Verificar si el script existe    
            
            # Ejecutar el script de Node.js en segundo plano
            # Inicio Carlos
            process = subprocess.Popen([
                "node", 
                script_path, 
                quote_url, 
                output_path,
                token
            ], start_new_session=True)
            # Esto esperará hasta que el proceso termine
            return_code = process.wait()
            # Obtener Correos para enviar el mensaje
            respuesta = Get_General_Information(quote_id)
            correo_customer = respuesta["Customer"]["CustomerEmail"]
            correo_Seller = respuesta["Seller"]["SellerEmail"]
            ruta_archivo_local = output_path  

            # Abrir el archivo en modo binario
            with open(ruta_archivo_local, 'rb') as f:
                # Crear un objeto FileStorage a partir del archivo
                technicalSheet = FileStorage(
                    stream=f,
                    filename=f"cotizacion_{token}.pdf",
                    name="TechnicalSheet"
                )
                # Ahora puedes usar este objeto con tu función
                ruta_pdf = "/domains/sycelephant.com/public_html/file/Ventas/EUA/Cotizaciones/"
                carpeta = "/Ventas/EUA/Cotizaciones/"
                item = f"cotizacion_{token}_{quote_id}"
                resultado = subir_archivo_ftp_desde_request(technicalSheet, item, ruta_pdf, carpeta)
                if resultado["exito"]:
                    filename = resultado["url_web"]
                    update_RoutePDF(filename,quote_id)
                    # Directorio a limpiar
                    directorio = output_dir 
                    resultado = eliminar_pdfs_en_directorio(directorio)
                    url_pdf = filename
                    correos_destino = [correo_customer, correo_Seller]
                    # Ejecutar la función  Enviar correo
                    is_production = not current_app.config.get('DEBUG', False)
                    #if not is_production:
                    if Productivo == False:
                        try:
                            # Asunto y mensaje
                            asunto_correo = "Cotización del proyecto"
                            quote_data = get_Definitive_quote_data(quote_id)
                            #Construir la tabla de la plannta General
                            CotizacionGenset_data = Get_CotizacionGenset_data(quote_id)
                            table_CotizacionGenset = generate_quote_table_Genset(CotizacionGenset_data)
                            price_CotizacionGenset = sum_total_prices(table_CotizacionGenset)
                            #Construir la tabla de los Breakers
                            CotizacionBreakers_data = Get_CotizacionBreakers_data(quote_id)
                            table_CotizacionBreakers = generate_quote_table_breakers(CotizacionBreakers_data)
                            price_CotizacionBreakers = sum_total_prices(table_CotizacionBreakers)
                            #Construir la tabla del Control
                            CotizacionControl_data = Get_CotizacionControl_data(quote_id)
                            table_CotizacionControl = generate_quote_table_Control(CotizacionControl_data)
                            price_CotizacionControl = sum_total_prices(table_CotizacionControl)
                            #Construir la tabla de la caseta
                            CotizacionEnclosure_data = Get_CotizacionEnclosure_data(quote_id)
                            table_CotizacionEnclosure = generate_quote_table_Enclosure(CotizacionEnclosure_data)
                            price_CotizacionEnclosure = sum_total_prices(table_CotizacionEnclosure)
                            #Construir la tabla de los accesorios
                            CotizacionAccesories_data = Get_CotizacionAccesories_data(quote_id)
                            table_CotizacionAccesories = generate_quote_table_Accesories(CotizacionAccesories_data)
                            price_CotizacionAccesories = sum_total_prices(table_CotizacionAccesories)
                            #Construir la tabla del Tanque
                            CotizacionTank_data = Get_CotizacionTank_data(quote_id)
                            table_CotizacionTank = generate_quote_table_Tank(CotizacionTank_data)
                            price_CotizacionTank = sum_total_prices(table_CotizacionTank)
                            Genset_price = price_CotizacionGenset + price_CotizacionBreakers + price_CotizacionControl + price_CotizacionEnclosure + price_CotizacionAccesories + price_CotizacionTank
                            #Construir la tabla de las pruebas
                            CotizacionWarrantyAndTest_data = Get_warranty_and_testing_pricing(quote_id, Genset_price)  
                            table_WarrantyAndTest = generate_quote_table_WT(CotizacionWarrantyAndTest_data)
                            price_WarrantyAndTest = sum_total_prices(table_WarrantyAndTest)
                            GranTotal = Genset_price + price_WarrantyAndTest

                            #Obtener el valor de descuento por pais
                            countryDiscountData = get_country_discont(quote_id, GranTotal)
                           




                            DATE = datetime.now().strftime("%Y-%m-%d")
                            data = {
                            "quote_id": quote_id,
                            "date": {
                                "DATE": DATE,
                            },
                            "project_info": {
                                    "project": quote_data['Project'],
                                    "customer_requirements": quote_data['ReqCustomer']
                                },
                            "Customer": {
                                    "CustomerCompany": quote_data['CustomerCompany'],
                                    "CustomerAddress": quote_data['CustomerAddress'],
                                    "CustomerContact": quote_data['CustomerContact'],
                                    "CustomerEmail": quote_data['CustomerEmail'],
                                    "CustomerTel": quote_data['CustomerTel']
                                },
                            "Seller": {
                                    "SellerName": quote_data['SellerName'],
                                    "SellerEmail": quote_data['SellerEmail'],
                                    "SellerPhone": quote_data['SellerPhone']
                                },
                            "context" : {
                                    "price_CotizacionGenset": price_CotizacionGenset,
                                    "price_CotizacionBreakers": price_CotizacionBreakers,
                                    "price_CotizacionControl": price_CotizacionControl,
                                        "price_CotizacionEnclosure": price_CotizacionEnclosure,
                                    "price_CotizacionAccesories": price_CotizacionAccesories,
                                    "price_CotizacionTank": price_CotizacionTank,
                                    "price_WarrantyAndTest": price_WarrantyAndTest,
                                    "GranTotal": GranTotal,
                                    'countryData': countryDiscountData, # Contiene los datos de descuentos.
                                    "countryDiscount": quote_data['Country_Discount'],
                                    "today_date": datetime.now().strftime('%d/%m/%Y'),
                                    "quote_id": quote_id
                            }
                            }
                            # Descargar el PDF si es una URL
                            if url_pdf.startswith(('http://', 'https://')):
                                try:
                                    respuesta = requests.get(url_pdf)
                                    respuesta.raise_for_status()  # Verificar si la descarga fue exitosa
                                    # Guardar temporalmente el PDF
                                    with NamedTemporaryFile(delete=False, suffix='.pdf') as temp_file:
                                        temp_file.write(respuesta.content)
                                        temp_path = temp_file.name
                                except Exception as e:
                                    print(f"ERROR: Fallo al descargar PDF: {str(e)}")
                                    raise
                            else:
                                # Es una ruta de archivo local
                                if not os.path.exists(url_pdf):
                                    print(f"ERROR: El archivo {url_pdf} no existe")
                                    raise FileNotFoundError(f"El archivo {url_pdf} no existe")
                                temp_path = url_pdf
                                
                            # Renderizar el cuerpo del correo utilizando la plantilla HTML
                            cuerpo_html = render_template('/Ventas/VentasEUA/Mail/VEUcotizadormail.html', data=data)
                            # Crear el mensaje
                            msg = Message(
                                asunto_correo,
                                sender=app.config['MAIL_USERNAME'],
                                recipients=correos_destino  # Pasar directamente la lista
                            )
                            # Asignar el cuerpo HTML (una sola vez)
                            msg.html = cuerpo_html
                            # Adjuntar el PDF
                            nombre_archivo = os.path.basename(url_pdf) or "documento.pdf"
                            try:
                                with open(temp_path, 'rb') as file:
                                    file_data = file.read()
                                    msg.attach(
                                        filename=nombre_archivo,
                                        content_type='application/pdf',
                                        data=file_data
                                    )
                            except Exception as e:
                                print(f"ERROR: Error al adjuntar archivo: {str(e)}")
                                raise
                            # Enviando el correo
                            try:
                                mail.send(msg)
                            except Exception as e:
                                print(f"ERROR: Excepción al enviar correo: {str(e)}")
                                # Si tienes acceso a más detalles de la excepción, muéstralos
                                import traceback
                                print(f"ERROR: Detalles del error: {traceback.format_exc()}")
                                raise
                            # Eliminar el archivo temporal solo si se descargó
                            if url_pdf.startswith(('http://', 'https://')) and os.path.exists(temp_path):
                                os.unlink(temp_path)
                            
                        except Exception as e:
                            # Asegurarse de eliminar el archivo temporal si existe
                            if 'temp_path' in locals() and os.path.exists(temp_path) and url_pdf.startswith(('http://', 'https://')):
                                os.unlink(temp_path)
                            print(f'-------------Error al enviar el correo:----------------------------{str(e)}')
                            
                else:
                    return jsonify({"error": resultado["mensaje"]}), 400
                
            #Fin Carlos
            # Devolver respuesta con el token para verificación posterior
            return jsonify({
                'status': 'processing',
                'token': token,
                'message': 'La generación del PDF ha iniciado.'
            })
        except Exception as e:
            import traceback
            traceback_str = traceback.format_exc()
            print(f"Error detallado: {traceback_str}")
            return jsonify({
                'status': 'error',
                'message': f'Error: {str(e)}'
            }), 500

    # Ruta para verificar el estado del PDF
    @app.route('/Ventas/VentasEUA/check_pdf_status/<quoteId>', methods=['GET'])
    def check_pdf_status(quoteId):
        # Obtiene la ruta base de la aplicación
        Rutapdf = get_RoutePDF(quoteId)
        Ruta_pdf = str(Rutapdf)
        is_production = not current_app.config.get('DEBUG', False)
        #if is_production:
        if Productivo == True:
            ruta = Rutapdf['RoutePDF']
        else:
            base_url = request.host_url.rstrip('/')
            ruta = f"{base_url}/Ventas/Ventas_EUA/Cotizador_EUA"
            
        return jsonify({
                'status': 'completed',
                'pdf_path': Ruta_pdf,
                'ruta': ruta
            })
        
    def eliminar_pdfs_en_directorio(directorio):
        # Buscar todos los archivos PDF en el directorio
        patron_busqueda = os.path.join(directorio, "*.pdf")
        archivos_pdf = glob.glob(patron_busqueda)
        
        # Contador para estadísticas
        eliminados = 0
        fallidos = 0
        
        # Intentar eliminar cada archivo
        for archivo in archivos_pdf:
            try:
                os.remove(archivo)
                eliminados += 1
            except PermissionError:
                fallidos += 1
            except Exception as e:
                fallidos += 1
        
        return {"eliminados": eliminados, "fallidos": fallidos}

