enviador-de-ordenes 0.3.2
Enviador de Órdenes - Core engine para reportes y generación de PDFs para PYMEs
Requires Python: >=3.13

# 📦 **Enviador de Órdenes — README Oficial (Actualizado)**

> Sistema ligero, modular y escalable para cargar información desde Excel o entrada manual, generar **PDF profesionales**, y enviarlos automáticamente por **Telegram y Email**.
> Desarrollado en Python + Streamlit con un enfoque de DataOps para PYMEs.

---

# 🚀 **1. Requisitos previos**

### ✔ Python **3.13+**

Obligatorio (ReportLab + Streamlit funcionan perfecto en 3.13).

### ✔ uv — Gestor moderno recomendado

Instalar:

```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```

Verificar:

```bash
uv --version
```

---

# 🧩 **2. Clonar el repositorio**

```bash
git clone https://github.com/tu-org/enviador_de_ordenes.git
cd enviador_de_ordenes
```

---

# 📁 **3. Estructura real del proyecto**

```
.
├── .env
├── .env.example
├── LICENSE
├── pyproject.toml
├── README.md
├── uv.lock
│
└── src/enviador_de_ordenes/
    ├── app.py                     # UI principal Streamlit
    │
    ├── core/
    │   ├── config.py             # Carga y validación de .env
    │   ├── domain.py             # OrderForm, OrderItem (Pydantic)
    │   ├── email_sender.py       # SMTP email
    │   ├── input_factory.py      # Strategy pattern para inputs
    │   ├── logger.py             # Logging
    │   ├── parsers.py            # parse_excel_to_order_form()
    │   ├── pdf_generator.py      # generate_pdf() + show_pdf()
    │   ├── telegram_sender.py    # Envío Telegram
    │   └── utils/
    │       ├── dataframe_utils.py# Limpieza df
    │       └── pdf_utils.py      # Transformar items → DataFrame
    │
    ├── strategies/
    │   ├── excel_input.py        # Carga desde Excel
    │   └── manual_input.py       # Carga manual
    │
    ├── data/
    │   ├── history.db            # Base de datos SQLite (historial)
    │   ├── inbox/                # Archivos entrantes
    │   ├── logo.png              # Opcional
    │   └── logo.webp             # Opcional
    │
    ├── services/
    │   ├── report_service.py     # Servicios (no usado aún)
    │   └── scheduler.py          # Automatización (placeholder)
    │
    └── templates/
        ├── pdf/
        │   └── base_template.py  # Template profesional (Platypus)
        └── ui/
            └── styles.py         # Estilos UI Streamlit
```

---

# 🎛 **4. Instalación del entorno**

### Instalar dependencias:

```bash
uv sync
```

Esto:

* crea `.venv/`
* instala todas las dependencias
* genera `uv.lock`

---

# 🔧 **5. Activar (opcional)**

```bash
source .venv/bin/activate
```

---

# 🔐 **6. Configuración del archivo `.env`**

Copiar base:

```bash
cp .env.example .env
```

Editar:

---

## 📑 6.1. Integración con Google Sheets (Cuenta de servicio)

Si quieres guardar los pedidos en Google Sheets:

1. **Crear la cuenta de servicio**  
   - En Google Cloud Console, crea o selecciona un proyecto.  
   - Habilita la API de Google Sheets en ese proyecto.  
   - Ve a IAM y administración → Cuentas de servicio → Crear.  
   - Rol sugerido: **Editor** (o equivalente con acceso a Sheets).  
   - Genera **clave JSON** y descárgala.

2. **Compartir el Sheet**  
   - Crea tu spreadsheet en Google Sheets.  
   - Copia el ID del sheet (lo que va después de `/d/` en la URL).  
    - Comparte el sheet con el email de la cuenta de servicio con permiso de **Editor**.

3. **Agregar credenciales al `.env`** (elige una opción):
   - Opción archivo:
     ```
     GDRIVE_SERVICE_ACCOUNT_FILE=/ruta/credenciales.json
     ```
   - Opción base64 (pegar el JSON codificado):
     ```
     GDRIVE_SERVICE_ACCOUNT_BASE64=<json_codificado_en_base64>
     ```
     Para codificar el JSON en macOS/Linux: `base64 -w0 credenciales.json` (o `base64 credenciales.json | tr -d '\n'`).
   - Además:
     ```
     GOOGLE_SHEETS_ID=<id_del_spreadsheet>
     GOOGLE_SHEETS_WORKSHEET=Hoja1   # opcional
     ```

Listo: al procesar un pedido, la app intentará agregar las filas al sheet.

---

## 📲 6.1. Configurar el BOT de Telegram desde cero

### 1️⃣ Crear el bot en BotFather

1. Abre Telegram (móvil o escritorio).
2. Busca el usuario **@BotFather**.
3. Escribe `/start` si es la primera vez.
4. Envía el comando:

   ```text
   /newbot
   ```
5. BotFather te pedirá:

   * **Nombre del bot** (ej: `Enviador de Órdenes`)
   * **Username del bot** (debe terminar en `bot`, por ejemplo: `enviador_ordenes_bot`).
6. Al final te devolverá algo así:

   ```text
   Use this token to access the HTTP API:
   1234567890:ABCDefGhIJKlmNoPQRstuVWxyZ
   ```
7. Ese valor es tu **`TELEGRAM_BOT_TOKEN`** → guárdalo en `.env`:

   ```env
   TELEGRAM_BOT_TOKEN="1234567890:ABCDefGhIJKlmNoPQRstuVWxyZ"
   ```

---

### 2️⃣ Activar el bot (importante)

1. Desde tu cuenta de Telegram, **busca el bot** por el username que creaste (ej: `@enviador_ordenes_bot`).
2. Ábrelo y presiona **Start** o envíale cualquier mensaje (ej: `Hola`).
3. Sin ese primer mensaje, el bot no puede escribirte.

---

### 3️⃣ Obtener el CHAT ID (conversación 1 a 1)

Opción A — vía API oficial:

1. Después de escribirle al bot, abre en el navegador:

   ```text
   https://api.telegram.org/bot<TELEGRAM_BOT_TOKEN>/getUpdates
   ```

2. Busca algo como:

   ```json
   "message": {
     "chat": {
       "id": 987654321,
       "first_name": "...",
       ...
     }
   }
   ```

3. Ese `987654321` es tu **`TELEGRAM_CHAT_ID`**.
   Configúralo en `.env`:

   ```env
   TELEGRAM_CHAT_ID="987654321"
   ```

Opción B — con bots tipo `@userinfobot` (por si algún día te toca):

1. Habla con **@userinfobot**.
2. Te responde tu `id`.
3. Usas ese número como `TELEGRAM_CHAT_ID`.

---

### 4️⃣ CHAT ID para grupos (por si lo usas más adelante)

1. Crea un grupo e incluye a tu bot.

2. En el grupo, escribe un mensaje y luego consulta:

   ```text
   https://api.telegram.org/bot<TELEGRAM_BOT_TOKEN>/getUpdates
   ```

3. Verás un `chat.id` negativo, algo tipo:

   ```json
   "id": -1234567890123
   ```

4. Usa ese valor (con el signo menos) como `TELEGRAM_CHAT_ID`.

---

### 5️⃣ Resumen de variables que deben quedar en `.env`

```env
TELEGRAM_BOT_TOKEN="1234567890:ABCDefGhIJKlmNoPQRstuVWxyZ"
TELEGRAM_CHAT_ID="987654321"          # o ID negativo si es grupo
```

---

## 📧 6.2. Obtener la contraseña de aplicación de Gmail (SMTP)

> Esto es lo que siempre se olvida, así que lo dejamos paso a paso.

### 1️⃣ Activar la verificación en dos pasos (si no está activada)

1. Entra a **tu cuenta de Google**:
   [https://myaccount.google.com](https://myaccount.google.com)
2. Ve a **Seguridad** (Security).
3. En “Acceso a Google”, entra a **Verificación en dos pasos**.
4. Actívala (Google te va a guiar con SMS, app de autenticación, etc.).

Sin 2FA, **no aparece** la opción de “Contraseñas de aplicación”.

---

### 2️⃣ Crear una contraseña de aplicación

1. En la misma sección de seguridad, entra a:
   **Seguridad → Acceso a Google → Contraseñas de aplicaciones**
   (en inglés: *App passwords*).

2. Si te la pide, vuelve a iniciar sesión.

3. En el selector:

   * **Aplicación:** selecciona “Correo” (Mail) o “Otro (nombre personalizado)” y escribe algo como `Enviador de Órdenes`.
   * **Dispositivo:** puedes dejar “Otro” o “Este dispositivo”.

4. Haz clic en **Generar**.

5. Google te mostrará una contraseña de 16 caracteres, algo tipo:

   ```text
   abcd efgh ijkl mnop
   ```

6. **Copia esa contraseña** (sin espacios) y guárdala como `SMTP_PASSWORD` en `.env`.

---

### 3️⃣ Configurar las variables SMTP en `.env`

```env
SMTP_SERVER="smtp.gmail.com"
SMTP_PORT=587
SMTP_USER="tu-correo@gmail.com"
SMTP_PASSWORD="abcd efgh ijkl mnop"   # la contraseña de aplicación (puedes quitar espacios)
EMAIL_TO="destino1@empresa.com"
```

Puedes dejar la password con o sin espacios; lo más limpio:

```env
SMTP_PASSWORD="abcdefghijklnmop"
```

---

### 4️⃣ Notas importantes (para que no te estalle en producción)

* La **contraseña de aplicación NO es tu contraseña normal de Gmail**.
* Si cambias algo crítico en tu cuenta (2FA, recuperación, etc.), Google a veces invalida contraseñas de aplicación → si un día deja de enviar, revisa ahí primero.
* En entornos corporativos (Google Workspace), es posible que:

  * El admin bloquee contraseñas de aplicación.
  * Tengas que usar SMTP corporativo distinto (no `smtp.gmail.com`).

---

# 🖥️ **7. Ejecutar la UI**

```bash
uv run streamlit run src/enviador_de_ordenes/app.py
```

Funciones principales:

* Cargar Excel
* Ingreso manual con edición dinámica
* Validación automática de OrderForm
* PDF profesional (vertical, 2 columnas, multipágina)
* Vista previa del PDF embebida
* Enviar por **Telegram**
* Enviar por **Email**
* Historial en SQLite (opcional)

---

# 🧾 **8. Generación de PDF profesional**

El sistema usa:

### ✔ ReportLab + Platypus

### ✔ Template corporativo (`base_template.py`)

### ✔ Dos columnas por página (Frames)

### ✔ Repetición del encabezado en multipágina

### ✔ Resumen dinámico (OrderForm → PDF)

### ✔ Sin textos quemados (labels vienen del modelo)

### ✔ Logo corporativo opcional

PDF generado en:

```
src/enviador_de_ordenes/data/outbox/
```

---

# 🔄 **9. Flujo interno del sistema**

```
Excel / Manual input
       ↓
InputFactory (Strategy)
       ↓
parse_excel_to_order_form()
       ↓
OrderForm (Pydantic + metadata)
       ↓
generate_pdf(order)
       ↓
show_pdf()
       ↓
send_pdf_via_telegram()
send_pdf_email()
       ↓
history.db (pronto)
```

---

# 🧪 **10. Ejecutar módulos manualmente**

```bash
uv run python src/enviador_de_ordenes/core/pdf_generator.py
```

---

# 📦 **11. Empaquetar para PYMEs (.exe)**

```bash
uv add pyinstaller
uv run pyinstaller --onefile src/enviador_de_ordenes/app.py
```

Salida:

```
dist/app.exe
```

---

# 🛠 **12. Personalización**

## PDF

Editar:

```
src/enviador_de_ordenes/templates/pdf/base_template.py
```

Puedes cambiar:

* Logo
* Colores
* Márgenes
* Tipografías
* Numero de columnas
* Footer
* Distribución del resumen

## UI

Editar:

```
src/enviador_de_ordenes/templates/ui/styles.py
```

---

# 📌 **13. Qué copia un cliente para ejecutar**

* **Python 3.13**
* **uv**
* `.env` con Telegram/Email
* Toda la carpeta del proyecto
* Crear carpeta `data/outbox` (si no existe)

Con eso, corre sin dependencias adicionales.

---

# 🎉 **14. Créditos**

Desarrollado por Santiago Aguirre — Memento Software Factory

---