Skip to content

IsmaYKITIC/InvoiceGeneratorShopify

Repository files navigation

AppMail - Sistema de Facturación Automática para Shopify

📋 Introducción

AppMail es un servicio de automatización de facturas para tiendas Shopify que genera facturas en PDF a partir de pedidos y las envía automáticamente por correo electrónico al cliente final.

Cuando un cliente completa una compra en tu tienda Shopify, la plataforma envía automáticamente los datos del pedido a AppMail. El sistema procesa esta información, crea una factura profesional en PDF, la guarda en el servidor y la envía por email al cliente. Todo esto ocurre de forma automática en segundo plano, sin intervención manual.

La aplicación está desplegada en un servidor Ubuntu en la ruta /home/ubuntu/AppMail y responde en el dominio appmail.bruiser.es con conexión segura HTTPS.


🛠️ Tecnologías Utilizadas

Tecnología Versión ¿Para qué sirve?
Python 3.x Lenguaje de programación principal del proyecto
Flask - Framework web ligero para crear la API que recibe los webhooks
Gunicorn - Servidor de aplicaciones que ejecuta Flask en producción
Celery - Sistema de colas de tareas para procesar pedidos en segundo plano
Redis - Base de datos en memoria que actúa como "buzón" de tareas para Celery
Nginx - Servidor web que recibe las peticiones externas y las redirige a Gunicorn
Let's Encrypt (Certbot) - Proveedor de certificados SSL gratuitos para HTTPS
Gmail SMTP - Servicio de Google para enviar emails con las facturas
Ubuntu Server 20.04/22.04 Sistema operativo donde está desplegado todo
Systemd - Sistema de servicios de Linux que arranca automáticamente la aplicación

Librerías Python importantes:

  • Jinja2: Para generar el HTML de las facturas desde plantillas
  • WeasyPrint / ReportLab: Para convertir HTML a PDF
  • Requests: Para validar y procesar webhooks de Shopify
  • python-dotenv: Para cargar variables de entorno desde .env

📁 Estructura del Repositorio

AppMail/
│
├── 📄 README.md                    # Este archivo - documentación del proyecto
├── 📄 requirements.txt             # Lista de dependencias Python a instalar
├── 📄 .env                         # Variables de entorno (credenciales, configuración)
├── 📄 .gitignore                   # Archivos que Git debe ignorar
│
├── 📂 server/                      # Código del servidor web (Flask)
│   ├── 📄 __init__.py
│   ├── 📄 app.py                   # Aplicación Flask principal
│   ├── 📄 webhook_handler.py       # Lógica para recibir webhooks de Shopify
│   ├── 📄 security.py              # Validación de firmas HMAC de Shopify
│   └── 📂 __pycache__/
│
├── 📂 celery_app/                  # Configuración de tareas asíncronas (Celery)
│   ├── 📄 __init__.py              # Inicializa la aplicación Celery
│   ├── 📄 celery_config.py         # Configuración de Redis, serialización, rutas
│   ├── 📄 tasks.py                 # Definición de las tareas (generar PDF, enviar email)
│   └── 📂 __pycache__/
│
├── 📂 src/                         # Lógica de negocio del proyecto
│   ├── 📄 models.py                # Modelos de datos (pedido, cliente, producto)
│   ├── 📄 invoice_validator.py     # Valida que los datos del pedido sean correctos
│   ├── 📄 pdf_generator.py         # Genera el PDF de la factura
│   ├── 📄 email_sender.py          # Envía emails con la factura adjunta
│   ├── 📄 shopify_client.py        # Cliente para comunicarse con API de Shopify (si aplica)
│   └── 📂 __pycache__/
│
├── 📂 config/                      # Archivos de configuración
│   ├── 📄 __init__.py
│   ├── 📄 settings.py              # Configuración general de la aplicación
│   └── 📄 translations.py          # Traducciones de textos (español, catalán, etc.)
│
├── 📂 templates/                   # Plantillas HTML
│   └── 📄 invoice_template.html    # Plantilla HTML base para generar las facturas
│
├── 📂 invoices/                    # Carpeta donde se guardan las facturas generadas
│   ├── 📄 factura_6226.pdf
│   ├── 📄 factura_6227.pdf
│   ├── 📄 factura_6228.pdf
│   └── ...
│
├── 📂 logs/                        # Registros de actividad de la aplicación
│   ├── 📂 celery/                  # Logs del worker de Celery
│   │   └── 📄 processed_orders.json
│   └── 📄 app.log                  # Logs generales de Flask
│
├── 📂 storage/                     # Almacenamiento temporal
│   └── 📄 pending_invoices.json    # Facturas pendientes de procesar
│
├── 📂 tests/                       # Tests unitarios y de integración
│   │── 📄 __init__.py
│   
│   
│
├── 📄 run_server.py                # Script para arrancar el servidor Flask manualmente
├── 📄 run_celery_worker.sh         # Script para arrancar Celery manualmente
├── 📄 run_flower.sh                # Script para arrancar Flower (monitor de Celery)
│
└── 📂 .venv/                       # Entorno virtual de Python (no se sube a Git)
    └── ...

Descripción de carpetas principales:

  • server/: Contiene todo lo relacionado con Flask (la API web). Aquí se reciben los webhooks de Shopify y se valida que sean auténticos.

  • celery_app/: Aquí está la configuración de Celery, que es el sistema que procesa las tareas "pesadas" (generar PDF, enviar email) sin bloquear el servidor web.

  • src/: La lógica de negocio pura. Aquí están las funciones que realmente generan las facturas, validan datos y envían correos.

  • config/: Archivos de configuración general de la aplicación (rutas, idiomas, parámetros).

  • templates/: Plantillas HTML que se usan como "molde" para generar las facturas en PDF.

  • invoices/: Carpeta donde se guardan todas las facturas generadas en formato PDF.

  • logs/: Archivos de registro donde se guarda qué ha hecho la aplicación (útil para depurar errores).


🏗️ Arquitectura del Sistema

¿Cómo funciona todo junto?

Imagina que la aplicación es como una cadena de montaje en una fábrica:

  1. Shopify es el cliente que hace un pedido
  2. Nginx es el portero que recibe el pedido y lo pasa dentro
  3. Flask es el recepcionista que anota el pedido y lo pasa al taller
  4. Redis es el tablón donde se cuelgan los pedidos pendientes
  5. Celery Worker es el operario que toma un pedido del tablón y lo procesa
  6. PDF Generator es la máquina que imprime la factura
  7. Email Sender es el repartidor que envía la factura al cliente
┌─────────────────────────────────────────────────────────────────┐
│                         SHOPIFY STORE                            │
│                    (Cliente realiza pedido)                      │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             │ POST /webhook/orders/create
                             │ (Datos del pedido en JSON)
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                      SERVIDOR UBUNTU                             │
│                   /home/ubuntu/AppMail                           │
│                                                                  │
│  ┌────────────────────────────────────────────────────────┐    │
│  │              NGINX (Puerto 443 - HTTPS)                │    │
│  │  👮 "Portero" que recibe las peticiones externas       │    │
│  │     y las redirige internamente                        │    │
│  └──────────────────────┬─────────────────────────────────┘    │
│                         │                                       │
│                         │ Redirige a puerto 5000                │
│                         ▼                                       │
│  ┌────────────────────────────────────────────────────────┐    │
│  │         GUNICORN + FLASK (Puerto 5000)                 │    │
│  │  📝 "Recepcionista" que recibe el pedido               │    │
│  │     y lo valida                                        │    │
│  └──────────────────────┬─────────────────────────────────┘    │
│                         │                                       │
│                         │ Encola tarea                          │
│                         ▼                                       │
│  ┌────────────────────────────────────────────────────────┐    │
│  │              REDIS (Puerto 6379)                       │    │
│  │  📋 "Tablón de tareas pendientes"                      │    │
│  └──────────────────────┬─────────────────────────────────┘    │
│                         │                                       │
│                         │ Worker toma tarea                     │
│                         ▼                                       │
│  ┌────────────────────────────────────────────────────────┐    │
│  │         CELERY WORKER                                  │    │
│  │  👷 "Operario" que procesa el pedido                   │    │
│  │     en segundo plano                                   │    │
│  └──────────────────────┬─────────────────────────────────┘    │
│                         │                                       │
│                         ▼                                       │
│  ┌────────────────────────────────────────────────────────┐    │
│  │         LÓGICA DE NEGOCIO (src/)                       │    │
│  │  🏭 Genera PDF y envía email                           │    │
│  └──────────────────────┬─────────────────────────────────┘    │
│                         │                                       │
└─────────────────────────┼───────────────────────────────────────┘
                          │
                          ▼
                 ┌─────────────────┐
                 │   GMAIL SMTP    │
                 │  📧 Envía email │
                 └────────┬────────┘
                          │
                          ▼
                 ┌─────────────────┐
                 │  CLIENTE FINAL  │
                 │ ✅ Recibe factura│
                 └─────────────────┘

🔄 Flujo de un Pedido (Paso a Paso)

¿Qué pasa cuando un cliente compra algo?

FASE 1: Recepción del webhook ⚡ (Muy rápido - menos de 5 segundos)

  1. El cliente compra en la tienda Shopify
  2. Shopify envía un aviso (webhook) a nuestra URL: https://appmail.bruiser.es/webhook/orders/create
  3. Nginx recibe la petición y la redirige internamente a Flask
  4. Flask valida que el webhook sea legítimo (firma HMAC de seguridad)
  5. Flask guarda los datos del pedido en una cola de tareas
  6. Flask responde "OK" a Shopify inmediatamente

⚠️ Importante: Flask debe responder en menos de 5 segundos, por eso NO genera el PDF aquí. Solo lo apunta en la lista de pendientes.

FASE 2: Procesamiento en segundo plano 🔧 (72 h después)

  1. Celery Worker detecta que ha llegado el momento de procesar la tarea (se han cumplido las 72 h).
  2. Worker consulta Shopify usando el ID del pedido para obtener la información más reciente.
  3. Valida los datos Lee los datos de facturación desde los metafields de Shopify:
    • Si existen y están completos, se usan estos datos actualizados.
    • Si no existen o están vacíos, se usan los datos originales del webhook guardados al crear la tarea.
  4. Genera el PDF usando la plantilla HTML y los datos del pedido
  5. Guarda el PDF en la carpeta invoices/ con nombre factura_XXXX.pdf
  6. Prepara el email con el asunto, cuerpo y adjunta el PDF
  7. Envía el email al cliente usando Gmail SMTP
  8. Registra el resultado en los logs

🎯 Ventajas de esta Arquitectura

¿Por qué separar la recepción del procesamiento?

Sin Celery (Todo en Flask):

Shopify → Flask → [Genera PDF + Envía Email] → Responde a Shopify
                  ⏱️ Puede tardar 20-30 segundos
                  ❌ No se da margen al cliente para corregir datos
                  ❌ Riesgo de timeout y reintentos del webhook

Con Celery (Como está ahora):

Shopify → Flask → [Encola tarea diferida (+72 h)] → Responde "OK" a Shopify
                  ⏱️ Respuesta rápida (solo apuntar pedido)
                  ✅ Shopify recibe confirmación inmediata

72 h después...
Redis → Celery Worker → [Consulta metafields + Genera PDF + Envía Email]
        ⏱️ Puede tardar lo que haga falta, ya no afecta a Shopify

Beneficios:

  • Rapidez en la respuesta: Shopify recibe la confirmación casi al instante.
  • Periodo de corrección de 72 h: el cliente puede actualizar sus datos de facturación antes de emitir la factura.
  • Flexibilidad con el plan básico de Shopify: se usan metafields para suplir la falta de campos avanzados en la API estándar.
  • Escalabilidad: se pueden añadir más workers de Celery para procesar muchas facturas en paralelo sin saturar el servidor web.
  • Fiabilidad: si falla la generación del PDF o el envío del email, no se pierde el webhook ni se rompe la experiencia en Shopify.
  • Monitoreo: Los logs de Celery son independientes de Flask

🔐 Variables de Entorno Importantes

El archivo .env contiene información sensible que NO se ha subido a Git. si lo necesitas esta en el servidor :) Aquí están las principales variables:

SHOPIFY_SHOP_NAME=bruiser-es
SHOPIFY_ACCESS_TOKEN=XXXXXXX
SHOPIFY_API_VERSION=2024-01
# Shopify Configuration

# Webhook Security (lo obtienes después de crear el webhook en Shopify)
WEBHOOK_SECRET=XXXXXXX


# Redis (para Celery)
REDIS_URL=redis://localhost:6379/0

# Gmail SMTP
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=XXXXXXX@gmail.com
SMTP_PASSWORD=XXXXXXX

# Rutas de la aplicación
INVOICE_DIR=/home/ubuntu/AppMail/invoices/
LOG_DIR=/home/ubuntu/AppMail/logs/

🔒 Nota de seguridad: Para Gmail, debes usar una "contraseña de aplicación", NO tu contraseña normal. Se genera desde la configuración de seguridad de tu cuenta de Google.


📚 Próximos Pasos

Esta documentación continuará con:

  • Instalación: Cómo desplegar AppMail desde cero en un servidor nuevo
  • Configuración de servicios: Cómo configurar los servicios de systemd
  • Guía de uso: Cómo probar que todo funciona correctamente
  • Mantenimiento: Cómo ver logs, reiniciar servicios y solucionar problemas comunes

Para completar estas secciones, necesitaremos revisar los archivos de configuración específicos del proyecto.


👥 Para Nuevos Desarrolladores

Si eres nuevo en el proyecto, aquí tienes un glosario de conceptos clave:

  • Webhook: Es como un "timbrazo" que Shopify da a nuestra aplicación cuando pasa algo (ej: nuevo pedido)
  • API: Interfaz que permite a dos aplicaciones comunicarse (Shopify habla con nuestra app)
  • HTTPS: Protocolo seguro de internet (el candado que ves en el navegador)
  • SSL/TLS: Certificado digital que hace posible HTTPS
  • Asíncrono: Una tarea que se ejecuta "por separado" sin bloquear otras operaciones
  • Cola de tareas: Una lista de trabajos pendientes que se procesan uno por uno
  • SMTP: Protocolo para enviar emails
  • JSON: Formato de datos que usa Shopify para enviarnos información
  • PDF: Formato de documento portable (la factura que recibe el cliente)
  • Worker: Programa que trabaja en segundo plano procesando tareas

🧩 Servicios del sistema (systemd)

En el servidor se han creado servicios del sistema para que la aplicación se ejecute de forma automática, se pueda reiniciar fácilmente y quede bien integrada con Ubuntu.
Estos servicios se gestionan con systemd, el sistema de servicios de la mayoría de distribuciones Linux.

🤔 ¿Por qué se han creado estos servicios?

  • Para que AppMail (API Flask) y el worker de Celery se inicien automáticamente al arrancar el servidor.
  • Para poder ver su estado, reiniciarlos y ver logs con comandos simples.
  • Para tener una forma estándar y segura de ejecutar la aplicación en producción (sin depender de lanzar scripts a mano).

🧱 Servicios principales

appmail.service – Servidor web (Flask + Gunicorn)

Este servicio se encarga de arrancar la aplicación web (Flask) a través de Gunicorn.

  • Escucha peticiones que le llegan desde Nginx (por ejemplo en el puerto interno 5000).
  • Atiende los webhooks de Shopify y los endpoints de la API (como /webhook/orders/create).
  • Es el “cerebro” que recibe las peticiones y encola las tareas para Celery.

En resumen, appmail = servidor de la API Flask en producción (detrás de Nginx).


celery-worker.service – Procesamiento en segundo plano

Este servicio arranca el worker de Celery que procesa las tareas pendientes.

  • Lee las tareas desde Redis.
  • Se encarga de generar las facturas PDF y enviar los emails a los clientes.
  • Permite que el trabajo pesado se haga en segundo plano, sin bloquear la API.

En resumen, celery-worker = “motor” que hace el trabajo de fondo (facturas y correos).


⚙️ Comandos básicos de administración

Ver estado de los servicios

sudo systemctl status appmail
sudo systemctl status celery-worker

    - Muestran si el servicio está activo, parado o si ha fallado.

    - También muestran la hora del último inicio y algunos mensajes recientes.

Reiniciar servicios

sudo systemctl restart appmail
sudo systemctl restart celery-worker

    - Útil cuando se despliega una nueva versión del código o se cambian configuraciones.

    - Detiene el servicio y lo vuelve a arrancar con la versión actual del código.

Detener servicios

sudo systemctl stop appmail
sudo systemctl stop celery-worker

    - Detienen por completo la aplicación web o el worker de Celery.

    - Útil para mantenimiento, cambios en el servidor o diagnósticos.

Iniciar servicios

sudo systemctl start appmail
sudo systemctl start celery-worker

    - Arrancan el servicio si está parado.

    - Se usan después de un stop o en un servidor recién configurado.

Ver logs en tiempo real

sudo journalctl -u appmail -f
sudo journalctl -u celery-worker -f

    - Muestran los logs que genera cada servicio en directo (-f = follow).

    - Muy útil para ver qué ocurre al hacer un pedido de prueba o al reiniciar un servicio.

    - Si hay errores de arranque o de ejecución, normalmente aparecen aquí.

📊 Scripts de Monitoreo

El sistema incluye varios scripts Python en la carpeta scripts/ para monitorear y gestionar las facturas , Estos Sripts estan unicanete en el servidor:

Uso de Scripts

Ver Estado General

    > python3 scripts/check_status.py
    - Muestra un resumen del sistema: total de facturas, completadas, pendientes y emails enviados.

Ver Facturas Pendientes

    > python3 scripts/check_pending.py
    - Lista todas las facturas pendientes con el tiempo restante hasta su procesamiento automático. Indica cuáles están listas para procesar y cuándo será la próxima ejecución.

Consultar Factura Específica

    > python3 scripts/check_invoice.py {Id.order ex: *6238* }
    - Muestra el detalle completo de una factura: estado, datos del cliente, rutas de archivos, fechas de creación y procesamiento.

Verificar Servicios

    > python3 scripts/check_services.py
    - Comprueba que los servicios Celery (worker y beat) estén activos y  funcionando correctamente.

Forzar Procesamiento Manual

    > python3 scripts/force_process.py
    - Ejecuta manualmente la tarea de procesamiento de facturas que han cumplido las 72 horas, sin esperar a la próxima ejecución automática.

Copia y pega esta sección en tu README.md. Está formateada con sintaxis Markdown e incluye ejemplos de uso para cada script.[1]

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors