Inventario de Productos con Python + Flask + ReportLab

- Si es de tu interés este artículo, apoyanos compartiendo en tus redes sociales favoritas y de esa manera también incentivando a tus amigos que crees les pueda interesar a que nos lean.


Inventario de Productos con Python + Flask + ReportLab


📌 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:

👉 http://127.0.0.1:5000/



No hay comentarios