%202.29.00%E2%80%AFa.m..png)
📌 Proyecto 5: Sistema de Inventario con Reportes en PDF en Flask
En este artículo, te mostraré cómo desarrollamos “Proyecto 5”, un sistema web de inventario con Flask y Python.
Este sistema permite:
✅ Agregar, editar y eliminar productos
✅ Gestionar categorías de productos
✅ Generar reportes en PDF con un formato profesional
✅ Guardar los datos en archivos .txt sin necesidad de una base de datos
🔹 Tecnologías Utilizadas
• Python + Flask: Backend para la lógica de negocio.
• HTML + Bootstrap: Interfaz moderna y responsiva.
• OS (módulo de Python): Manejo de archivos de inventario y categorías.
• ReportLab: Para generar reportes en PDF con diseño profesional.
📌 Estructura del Proyecto
Proyecto5/
├── templates/ # Carpeta para las plantillas HTML
│ ├── index.html # Página principal con formulario y lista de productos
│ ├── editar.html # Página para editar productos
│ ├── categorias.html # Página para agregar categorías
├── app.py # Código principal de Flask
├── generar_reporte.py # Script para generar el reporte en PDF
├── inventario.txt # Archivo donde se guardan los productos
├── categorias.txt # Archivo donde se guardan las categorías
📌 Código Fuente Completo
🔹 1. app.py - Aplicación Flask
Este archivo maneja la lógica del sistema, permitiendo gestionar productos, categorías y generar reportes en PDF.
from flask import Flask, render_template, request, redirect, url_for, send_file
import os
import datetime
from generar_reporte import generar_pdf
app = Flask(__name__)
# Rutas de archivos
documents_path = os.path.join(os.path.expanduser("~"), "Documents")
folder_path = os.path.join(documents_path, "python", "Proyecto5")
file_path = os.path.join(folder_path, "inventario.txt")
categories_path = os.path.join(folder_path, "categorias.txt")
# Asegurar que la carpeta existe
if not os.path.exists(folder_path):
os.makedirs(folder_path)
# Función para leer datos desde un archivo
def leer_datos(archivo):
if not os.path.exists(archivo):
return []
with open(archivo, "r", encoding="utf-8") as file:
return [line.strip().split(",") for line in file.readlines()]
# Función para escribir datos en un archivo
def escribir_datos(archivo, datos):
with open(archivo, "w", encoding="utf-8") as file:
for item in datos:
file.write(",".join(item) + "\n")
@app.route('/')
def index():
productos = leer_datos(file_path)
categorias = leer_datos(categories_path)
return render_template('index.html', productos=enumerate(productos), categorias=categorias)
@app.route('/agregar', methods=['POST'])
def agregar():
nombre = request.form['nombre']
categoria = request.form['categoria']
cantidad = request.form['cantidad']
precio = request.form['precio']
fecha = datetime.datetime.now().strftime("%Y-%m-%d")
nuevo_producto = [nombre, categoria, cantidad, precio, fecha]
productos = leer_datos(file_path)
productos.append(nuevo_producto)
escribir_datos(file_path, productos)
return redirect(url_for('index'))
@app.route('/generar_reporte')
def generar_reporte():
return send_file(generar_pdf(), as_attachment=True)
if __name__ == '__main__':
app.run(debug=True)
🔹 2. generar_reporte.py - Generación del Reporte en PDF
Este archivo genera el reporte en PDF con formato de tabla y estilo profesional.
import os
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
from reportlab.lib.units import inch
# Rutas de archivos
documents_path = os.path.join(os.path.expanduser("~"), "Documents")
folder_path = os.path.join(documents_path, "python", "Proyecto5")
file_path = os.path.join(folder_path, "inventario.txt")
pdf_path = os.path.join(folder_path, "reporte_inventario.pdf")
# Función para leer productos desde el archivo
def leer_productos():
if not os.path.exists(file_path):
return []
with open(file_path, "r", encoding="utf-8") as file:
return [line.strip().split(",") for line in file.readlines()]
def generar_pdf():
productos = leer_productos()
if not productos:
return None
pdf = SimpleDocTemplate(pdf_path, pagesize=letter)
contenido = []
encabezado = [["Nombre del Producto", "Categoría", "Cantidad", "Precio", "Fecha de Registro"]]
for prod in productos:
encabezado.append([prod[0], prod[1], prod[2], f"${prod[3]}", prod[4]])
tabla = Table(encabezado, colWidths=[2.5*inch, 2*inch, 1*inch, 1*inch, 1.5*inch])
estilo = TableStyle([
('BACKGROUND', (0, 0), (-1, 0), colors.darkblue),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
('BACKGROUND', (0, 1), (-1, -1), colors.beige),
('GRID', (0, 0), (-1, -1), 1, colors.black)
])
tabla.setStyle(estilo)
contenido.append(tabla)
pdf.build(contenido)
return pdf_path
🔹 3. templates/index.html - Interfaz Principal
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sistema de Inventario</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-dark text-light">
<div class="container mt-5">
<h2 class="text-center">📦 Inventario de Productos</h2>
<form action="/agregar" method="POST" class="card p-4 shadow mb-4 bg-secondary text-light">
<div class="mb-3">
<label class="form-label">Nombre</label>
<input type="text" class="form-control" name="nombre" required>
</div>
<div class="mb-3">
<label class="form-label">Categoría</label>
<select class="form-control" name="categoria" required>
{% for categoria in categorias %}
<option value="{{ categoria[0] }}">{{ categoria[0] }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">Agregar Producto</button>
</form>
<a href="/generar_reporte" class="btn btn-warning">📄 Generar Reporte</a>
</div>
</body>
</html>
🚀 Cómo Ejecutar
1️⃣ Instalar dependencias:
pip install flask reportlab
2️⃣ Ejecutar Flask:
python app.py
3️⃣ Abrir en el navegador:
No hay comentarios