Bladeren bron

migrate to pgsql

Matthew Trejo 3 dagen geleden
bovenliggende
commit
67b9e7c0cb
7 gewijzigde bestanden met toevoegingen van 192 en 7 verwijderingen
  1. 16 5
      README.md
  2. BIN
      __pycache__/app.cpython-313.pyc
  3. BIN
      __pycache__/routes.cpython-313.pyc
  4. 5 1
      app.py
  5. 4 0
      requirements.txt
  6. 44 0
      routes.py
  7. 123 1
      templates/configuracion.html

+ 16 - 5
README.md

@@ -1,6 +1,12 @@
 # Calculadora de Viabilidad Solar
 # Calculadora de Viabilidad Solar
 
 
 Aplicación web en Flask para calcular la viabilidad de proyectos de energía solar fotovoltaica.
 Aplicación web en Flask para calcular la viabilidad de proyectos de energía solar fotovoltaica.
+**Nota:** El sistema ha sido migrado a PostgreSQL.
+
+## Requisitos
+
+- Python 3.8+
+- PostgreSQL
 
 
 ## Inicio Rápido
 ## Inicio Rápido
 
 
@@ -12,15 +18,20 @@ Aplicación web en Flask para calcular la viabilidad de proyectos de energía so
    pip install -r requirements.txt
    pip install -r requirements.txt
    ```
    ```
 
 
-2. **Ejecutar:**
+2. **Configuración de Base de Datos:**
+   - Asegúrate de tener un servidor PostgreSQL corriendo.
+   - Crea una base de datos llamada `solarcalc`.
+   - Verifica la cadena de conexión en `app.py` (`SQLALCHEMY_DATABASE_URI`) para asegurar que apunta a tu instancia de base de datos correcta.
+
+3. **Ejecutar:**
    ```bash
    ```bash
    python app.py
    python app.py
    ```
    ```
-   Accede a `http://127.0.0.1:5000`.0,15
+   Accede a `http://127.0.0.1:5000`.
 
 
 ## Estructura
 ## Estructura
 
 
-- `app.py`: Aplicación principal.
-- `models.py`: Modelos de datos.
-- `routes.py`: Rutas.
+- `app.py`: Aplicación principal y configuración de PostgreSQL.
+- `models.py`: Modelos de datos (SQLAlchemy).
+- `routes.py`: Rutas y lógica del controlador.
 - `templates/`: Vistas HTML.
 - `templates/`: Vistas HTML.

BIN
__pycache__/app.cpython-313.pyc


BIN
__pycache__/routes.cpython-313.pyc


+ 5 - 1
app.py

@@ -1,9 +1,13 @@
+import os
 from flask import Flask
 from flask import Flask
 from models import db
 from models import db
 
 
 def create_app():
 def create_app():
     app = Flask(__name__)
     app = Flask(__name__)
-    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///solarcalc.db'
+    
+    # Configuración de la base de datos: PostgreSQL
+    # Formato PostgreSQL: postgresql://usuario:password@localhost:5432/nombre_db
+    app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:solarEn2026EsTodo@167.99.161.63:5432/solarcalc'
     app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
     app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
     app.config['SECRET_KEY'] = 'dev-secret-key-12345'
     app.config['SECRET_KEY'] = 'dev-secret-key-12345'
 
 

+ 4 - 0
requirements.txt

@@ -1,2 +1,6 @@
 Flask
 Flask
 Flask-SQLAlchemy
 Flask-SQLAlchemy
+psycopg2-binary
+
+
+

+ 44 - 0
routes.py

@@ -17,6 +17,7 @@ def configuracion():
     config_precio = Configuracion.query.filter_by(clave='precio_kwh').first()
     config_precio = Configuracion.query.filter_by(clave='precio_kwh').first()
     ciudades = DatosSolaresCiudad.query.all()
     ciudades = DatosSolaresCiudad.query.all()
     casas = Casa.query.all()
     casas = Casa.query.all()
+    paneles = CatalogoPaneles.query.all()
     
     
     edit_id = request.args.get('edit_id')
     edit_id = request.args.get('edit_id')
     casa_editar = None
     casa_editar = None
@@ -38,6 +39,7 @@ def configuracion():
                            precio_kwh=config_precio.valor if config_precio else '0.15', 
                            precio_kwh=config_precio.valor if config_precio else '0.15', 
                            ciudades=ciudades,
                            ciudades=ciudades,
                            casas=casas,
                            casas=casas,
+                           paneles=paneles,
                            casa_editar=casa_editar)
                            casa_editar=casa_editar)
 
 
 @main.route('/casa/editar/<int:id_casa>', methods=['POST'])
 @main.route('/casa/editar/<int:id_casa>', methods=['POST'])
@@ -68,6 +70,48 @@ def eliminar_casa(id_casa):
     flash('Casa eliminada correctamente.', 'success')
     flash('Casa eliminada correctamente.', 'success')
     return redirect(url_for('main.configuracion'))
     return redirect(url_for('main.configuracion'))
 
 
+@main.route('/panel/nuevo', methods=['POST'])
+def nuevo_panel():
+    marca = request.form.get('marca')
+    modelo = request.form.get('modelo')
+    eficiencia_r = float(request.form.get('eficiencia_r'))
+    area_m2 = float(request.form.get('area_m2'))
+    precio_unitario = float(request.form.get('precio_unitario'))
+    
+    panel = CatalogoPaneles(marca=marca, modelo=modelo, eficiencia_r=eficiencia_r, area_m2=area_m2, precio_unitario=precio_unitario)
+    db.session.add(panel)
+    db.session.commit()
+    flash('Panel agregado correctamente.', 'success')
+    return redirect(url_for('main.configuracion'))
+
+@main.route('/panel/editar/<int:id_panel>', methods=['POST'])
+def editar_panel(id_panel):
+    panel = CatalogoPaneles.query.get_or_404(id_panel)
+    panel.marca = request.form.get('marca')
+    panel.modelo = request.form.get('modelo')
+    panel.eficiencia_r = float(request.form.get('eficiencia_r'))
+    panel.area_m2 = float(request.form.get('area_m2'))
+    panel.precio_unitario = float(request.form.get('precio_unitario'))
+    
+    db.session.commit()
+    flash('Panel actualizado correctamente.', 'success')
+    return redirect(url_for('main.configuracion'))
+
+@main.route('/panel/eliminar/<int:id_panel>', methods=['POST'])
+def eliminar_panel(id_panel):
+    panel = CatalogoPaneles.query.get_or_404(id_panel)
+    
+    # Verificar si hay proyectos usando este panel
+    proyectos = ProyectosUsuario.query.filter_by(id_panel=id_panel).first()
+    if proyectos:
+        flash('No se puede eliminar este panel porque hay proyectos asociados a él.', 'danger')
+        return redirect(url_for('main.configuracion'))
+        
+    db.session.delete(panel)
+    db.session.commit()
+    flash('Panel eliminado correctamente.', 'success')
+    return redirect(url_for('main.configuracion'))
+
 @main.route('/casas')
 @main.route('/casas')
 def casas():
 def casas():
     casas = Casa.query.all()
     casas = Casa.query.all()

+ 123 - 1
templates/configuracion.html

@@ -75,10 +75,70 @@
                 {% endif %}
                 {% endif %}
             </div>
             </div>
         </div>
         </div>
+
+        <div class="card mb-4">
+            <div class="card-header bg-success text-white d-flex justify-content-between align-items-center">
+                <span>Gestión de Paneles Solares</span>
+                <button type="button" class="btn btn-light btn-sm" data-bs-toggle="modal" data-bs-target="#panelModal" onclick="setupPanelModal('new')">
+                    + Nuevo Panel
+                </button>
+            </div>
+            <div class="card-body">
+                <h5 class="card-title">Catálogo de Paneles</h5>
+                {% if paneles %}
+                <div class="table-responsive mb-4">
+                    <table class="table table-hover">
+                        <thead>
+                            <tr>
+                                <th>Marca</th>
+                                <th>Modelo</th>
+                                <th>Eficiencia</th>
+                                <th>Área (m²)</th>
+                                <th>Precio ($)</th>
+                                <th>Acciones</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                            {% for panel in paneles %}
+                            <tr>
+                                <td>{{ panel.marca }}</td>
+                                <td>{{ panel.modelo }}</td>
+                                <td>{{ panel.eficiencia_r }}</td>
+                                <td>{{ panel.area_m2 }}</td>
+                                <td>{{ panel.precio_unitario }}</td>
+                                <td>
+                                    <div class="btn-group" role="group">
+                                        <button type="button" class="btn btn-sm btn-warning" 
+                                            data-bs-toggle="modal" 
+                                            data-bs-target="#panelModal"
+                                            onclick="setupPanelModal('edit', {
+                                                marca: '{{ panel.marca }}',
+                                                modelo: '{{ panel.modelo }}',
+                                                eficiencia_r: '{{ panel.eficiencia_r }}',
+                                                area_m2: '{{ panel.area_m2 }}',
+                                                precio_unitario: '{{ panel.precio_unitario }}'
+                                            }, '{{ url_for('main.editar_panel', id_panel=panel.id_panel) }}')">
+                                            Editar
+                                        </button>
+                                        <form action="{{ url_for('main.eliminar_panel', id_panel=panel.id_panel) }}" method="POST" onsubmit="return confirm('¿Estás seguro de eliminar este panel?');" style="display: inline;">
+                                            <button type="submit" class="btn btn-sm btn-danger">Eliminar</button>
+                                        </form>
+                                    </div>
+                                </td>
+                            </tr>
+                            {% endfor %}
+                        </tbody>
+                    </table>
+                </div>
+                {% else %}
+                <div class="alert alert-info mb-4">No hay paneles registrados.</div>
+                {% endif %}
+            </div>
+        </div>
     </div>
     </div>
 </div>
 </div>
 
 
-<!-- Modal -->
+<!-- Modal Casa -->
 <div class="modal fade" id="casaModal" tabindex="-1" aria-labelledby="casaModalLabel" aria-hidden="true">
 <div class="modal fade" id="casaModal" tabindex="-1" aria-labelledby="casaModalLabel" aria-hidden="true">
     <div class="modal-dialog">
     <div class="modal-dialog">
         <div class="modal-content">
         <div class="modal-content">
@@ -131,6 +191,45 @@
     </div>
     </div>
 </div>
 </div>
 
 
+<!-- Modal Panel -->
+<div class="modal fade" id="panelModal" tabindex="-1" aria-labelledby="panelModalLabel" aria-hidden="true">
+    <div class="modal-dialog">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title" id="panelModalLabel">Gestión de Panel Solar</h5>
+                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+            </div>
+            <div class="modal-body">
+                <form id="panelForm" method="POST" action="{{ url_for('main.nuevo_panel') }}">
+                    <div class="mb-3">
+                        <label for="marca" class="form-label">Marca</label>
+                        <input type="text" name="marca" id="marca" class="form-control" required>
+                    </div>
+                    <div class="mb-3">
+                        <label for="modelo" class="form-label">Modelo</label>
+                        <input type="text" name="modelo" id="modelo" class="form-control" required>
+                    </div>
+                    <div class="mb-3">
+                        <label for="eficiencia_r" class="form-label">Eficiencia (0.0 - 1.0)</label>
+                        <input type="number" step="0.01" name="eficiencia_r" id="eficiencia_r" class="form-control" required>
+                    </div>
+                    <div class="mb-3">
+                        <label for="area_m2" class="form-label">Área (m²)</label>
+                        <input type="number" step="0.01" name="area_m2" id="area_m2" class="form-control" required>
+                    </div>
+                    <div class="mb-3">
+                        <label for="precio_unitario" class="form-label">Precio Unitario ($)</label>
+                        <input type="number" step="0.01" name="precio_unitario" id="precio_unitario" class="form-control" required>
+                    </div>
+                    <div class="d-grid">
+                        <button type="submit" class="btn btn-primary" id="panelModalSubmitBtn">Guardar Panel</button>
+                    </div>
+                </form>
+            </div>
+        </div>
+    </div>
+</div>
+
 <script>
 <script>
 function setupModal(mode, data, actionUrl) {
 function setupModal(mode, data, actionUrl) {
     const form = document.getElementById('casaForm');
     const form = document.getElementById('casaForm');
@@ -155,5 +254,28 @@ function setupModal(mode, data, actionUrl) {
         document.getElementById('inclinacion').value = data.inclinacion;
         document.getElementById('inclinacion').value = data.inclinacion;
     }
     }
 }
 }
+
+function setupPanelModal(mode, data, actionUrl) {
+    const form = document.getElementById('panelForm');
+    const title = document.getElementById('panelModalLabel');
+    const btn = document.getElementById('panelModalSubmitBtn');
+    
+    if (mode === 'new') {
+        title.textContent = 'Agregar Nuevo Panel';
+        btn.textContent = 'Guardar Panel';
+        form.action = "{{ url_for('main.nuevo_panel') }}";
+        form.reset();
+    } else if (mode === 'edit') {
+        title.textContent = 'Editar Panel';
+        btn.textContent = 'Actualizar Panel';
+        form.action = actionUrl;
+        
+        document.getElementById('marca').value = data.marca;
+        document.getElementById('modelo').value = data.modelo;
+        document.getElementById('eficiencia_r').value = data.eficiencia_r;
+        document.getElementById('area_m2').value = data.area_m2;
+        document.getElementById('precio_unitario').value = data.precio_unitario;
+    }
+}
 </script>
 </script>
 {% endblock %}
 {% endblock %}