first commit
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
# API Reference
|
||||
|
||||
## Descripción General
|
||||
|
||||
DataTransferV2 incluye una API REST construida con Flask para consultar y descargar datos de reportes.
|
||||
|
||||
## Base URL
|
||||
|
||||
```
|
||||
http://localhost:5000/api
|
||||
```
|
||||
|
||||
## Endpoints
|
||||
|
||||
### GET /download
|
||||
|
||||
Descarga datos de un reporte específico en formato JSON.
|
||||
|
||||
#### Parámetros de Query
|
||||
|
||||
| Parámetro | Tipo | Requerido | Descripción |
|
||||
|-----------|------|-----------|-------------|
|
||||
| project | string | Sí | Nombre del proyecto (pg, feduro) |
|
||||
| task | string | Sí | Nombre del reporte |
|
||||
| start_date | string | Sí | Fecha inicio (YYYY-MM-DD) |
|
||||
| end_date | string | Sí | Fecha fin (YYYY-MM-DD) |
|
||||
|
||||
#### Ejemplos de Uso
|
||||
|
||||
```bash
|
||||
# Cobertura PG
|
||||
curl "http://localhost:5000/api/download?project=pg&task=Cobertura&start_date=2024-01-01&end_date=2024-01-31"
|
||||
|
||||
# QualityDisplay FEDURO
|
||||
curl "http://localhost:5000/api/download?project=feduro&task=QualityDisplay&start_date=2024-01-15&end_date=2024-01-15"
|
||||
```
|
||||
|
||||
#### Respuesta Exitosa (200)
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"project": "pg",
|
||||
"task": "Cobertura",
|
||||
"start_date": "2024-01-01",
|
||||
"end_date": "2024-01-31",
|
||||
"data": [
|
||||
{
|
||||
"fecha": "2024-01-01",
|
||||
"tienda": "001",
|
||||
"categoria": "A",
|
||||
"ventas": 1500.50,
|
||||
"unidades": 25
|
||||
},
|
||||
{
|
||||
"fecha": "2024-01-02",
|
||||
"tienda": "001",
|
||||
"categoria": "B",
|
||||
"ventas": 2100.75,
|
||||
"unidades": 35
|
||||
}
|
||||
],
|
||||
"count": 62,
|
||||
"execution_time": "2.34s"
|
||||
}
|
||||
```
|
||||
|
||||
#### Respuestas de Error
|
||||
|
||||
##### 400 Bad Request - Parámetros Inválidos
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"message": "Parámetros requeridos faltantes: project, task, start_date, end_date",
|
||||
"code": 400
|
||||
}
|
||||
```
|
||||
|
||||
##### 404 Not Found - Proyecto/Reporte No Encontrado
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"message": "Proyecto 'invalid' no encontrado. Proyectos disponibles: pg, feduro",
|
||||
"code": 404
|
||||
}
|
||||
```
|
||||
|
||||
##### 500 Internal Server Error
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"message": "Error de conexión a base de datos",
|
||||
"code": 500
|
||||
}
|
||||
```
|
||||
|
||||
## Autenticación
|
||||
|
||||
Actualmente no requiere autenticación. Para producción, considera implementar:
|
||||
|
||||
- **Bearer Token:** `Authorization: Bearer <token>`
|
||||
- **API Key:** `X-API-Key: <key>`
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
No implementado actualmente. Recomendado para producción.
|
||||
|
||||
## Formatos de Datos
|
||||
|
||||
### Fechas
|
||||
- Formato: `YYYY-MM-DD`
|
||||
- Validación: Fechas válidas, start_date <= end_date
|
||||
|
||||
### Nombres de Proyecto
|
||||
- `pg`: Pentagono Group
|
||||
- `feduro`: Proyecto FEDURO
|
||||
- `corripio`: Proyecto Corripio (deshabilitado)
|
||||
|
||||
### Nombres de Reportes
|
||||
|
||||
#### PG (16 reportes)
|
||||
- Cobertura
|
||||
- Negociadas
|
||||
- Promociones
|
||||
- QualityDisplay
|
||||
- Checkout
|
||||
- QualityShelf
|
||||
- SOS
|
||||
- OsaAnalogo
|
||||
- OsaFotografico
|
||||
- Fmot
|
||||
- ModuloTareas
|
||||
- NegociadasIS001
|
||||
|
||||
#### FEDURO (18 reportes)
|
||||
- Cobertura
|
||||
- Checkout
|
||||
- OsaAnalogo
|
||||
- OsaFotografico
|
||||
- Promociones
|
||||
- QualityDisplay
|
||||
- QualityShelf
|
||||
- SOS
|
||||
- Fmot
|
||||
- ModuloTareas
|
||||
- NegociadasIS001
|
||||
|
||||
## Limitaciones
|
||||
|
||||
- **Máximo de registros:** No limitado (considera paginación)
|
||||
- **Timeout:** 30 segundos por defecto
|
||||
- **Formato de respuesta:** Solo JSON (considera CSV/XML)
|
||||
|
||||
## Ejemplos de Integración
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
url = "http://localhost:5000/api/download"
|
||||
params = {
|
||||
"project": "pg",
|
||||
"task": "Cobertura",
|
||||
"start_date": "2024-01-01",
|
||||
"end_date": "2024-01-31"
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params)
|
||||
data = response.json()
|
||||
|
||||
if data["status"] == "success":
|
||||
print(f"Obtenidos {data['count']} registros")
|
||||
# Procesar data["data"]
|
||||
```
|
||||
|
||||
### JavaScript
|
||||
|
||||
```javascript
|
||||
fetch('http://localhost:5000/api/download?project=pg&task=Cobertura&start_date=2024-01-01&end_date=2024-01-31')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
console.log(`Datos obtenidos: ${data.count} registros`);
|
||||
// Procesar data.data
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Monitoreo
|
||||
|
||||
Los requests a la API se registran en `Logs/api.log` con:
|
||||
- Timestamp
|
||||
- Endpoint
|
||||
- Parámetros
|
||||
- Tiempo de respuesta
|
||||
- Código de estado
|
||||
@@ -0,0 +1,81 @@
|
||||
# Arquitectura
|
||||
|
||||
## Descripción General
|
||||
|
||||
DataTransferV2 sigue una arquitectura modular basada en el patrón ETL (Extract-Transform-Load), con separación clara de responsabilidades en capas.
|
||||
|
||||
## Tecnologías Principales
|
||||
|
||||
- **Backend:** Python 3.x con Flask
|
||||
- **Base de Datos:** SQL Server (pyodbc)
|
||||
- **Procesamiento de Datos:** Pandas, OpenPyXL
|
||||
- **Distribución:** FTP (ftplib), SFTP (paramiko), SharePoint (office365), N8N webhooks
|
||||
- **Notificaciones:** WhatsApp via webhooks
|
||||
- **Programación:** APScheduler
|
||||
- **Contenedorización:** Docker, Docker Compose
|
||||
|
||||
## Estructura de Directorios
|
||||
|
||||
```
|
||||
DataTransferV2/
|
||||
├── main.py # Punto de entrada principal
|
||||
├── main2.py # Versión alternativa
|
||||
├── App/
|
||||
│ ├── Config/ # Configuraciones por proyecto
|
||||
│ ├── Services/ # Servicios core (ETL, API, UI)
|
||||
│ ├── Utils/ # Utilidades (DB, FTP, SFTP, etc.)
|
||||
│ ├── Models/ # Modelos de datos (vacío actualmente)
|
||||
│ ├── Static/ # Recursos estáticos para UI
|
||||
│ └── Templates/ # Plantillas HTML para UI
|
||||
├── requirements.txt # Dependencias Python
|
||||
├── Dockerfile # Configuración Docker
|
||||
├── docker-compose.yml # Orquestación de contenedores
|
||||
├── Tests/ # Pruebas
|
||||
├── Logs/ # Archivos de log
|
||||
└── Reportes/ # Reportes generados
|
||||
```
|
||||
|
||||
## Componentes Principales
|
||||
|
||||
### Capa de Configuración
|
||||
- **GeneralConfig.py:** Configuraciones globales (DB, notificaciones, zonas horarias)
|
||||
- **pgConfig.py:** Configuración específica para proyecto PG
|
||||
- **feduroConfig.py:** Configuración para proyecto FEDURO
|
||||
- **corripioConfig.py:** Plantilla para proyecto Corripio
|
||||
|
||||
### Capa de Servicios
|
||||
- **etl_service.py:** Motor de orquestación ETL
|
||||
- **api_service.py:** Endpoints REST API
|
||||
- **ui_service.py:** Interfaz web Flask
|
||||
|
||||
### Capa de Utilidades
|
||||
- **db_utils.py:** Gestor de conexiones y consultas SQL Server
|
||||
- **report_utils.py:** Generador de reportes Excel
|
||||
- **ftp_utils.py:** Cliente FTP con reintentos
|
||||
- **sftp_utils.py:** Cliente SFTP para Azure
|
||||
- **sharepoint_utils.py:** Integración con SharePoint
|
||||
- **notification_utils.py:** Envío de notificaciones WhatsApp
|
||||
|
||||
## Patrón de Diseño
|
||||
|
||||
### Patrón Manager
|
||||
Cada utilidad sigue el patrón Manager (DatabaseManager, FTPManager, etc.) para encapsular lógica específica.
|
||||
|
||||
### Patrón Pipeline
|
||||
El flujo ETL sigue un pipeline claro: Extract → Transform → Load, con manejo de errores resiliente.
|
||||
|
||||
### Configuración Centralizada
|
||||
Configuraciones separadas por proyecto permiten aislamiento y escalabilidad.
|
||||
|
||||
## Escalabilidad y Rendimiento
|
||||
|
||||
- **Procesamiento Paralelo:** Múltiples reportes procesados en secuencia
|
||||
- **Conexiones Pooling:** Reutilización de conexiones DB
|
||||
- **Reintentos Automáticos:** Para fallos en transferencias
|
||||
- **Logging Estructurado:** Para monitoreo y debugging
|
||||
|
||||
## Seguridad
|
||||
|
||||
- Autenticación Bearer tokens
|
||||
- Credenciales en configuración (considerar variables de entorno)
|
||||
- Conexiones encriptadas (SFTP, HTTPS)
|
||||
@@ -0,0 +1,248 @@
|
||||
# Configuración
|
||||
|
||||
## Archivos de Configuración
|
||||
|
||||
La configuración está organizada en archivos separados por proyecto en `App/Config/`.
|
||||
|
||||
## GeneralConfig.py
|
||||
|
||||
Configuraciones globales aplicables a todos los proyectos.
|
||||
|
||||
### Base de Datos
|
||||
|
||||
```python
|
||||
# SQL Server Connection
|
||||
SERVER = "sql.glmanalytics.com"
|
||||
DATABASES = {
|
||||
"pg": {"id": "00080001", "name": "glm_pg"},
|
||||
"feduro": {"id": "00010007", "name": "IS001"}
|
||||
}
|
||||
USERNAME = "tu_usuario"
|
||||
PASSWORD = "tu_password"
|
||||
```
|
||||
|
||||
### Zonas Horarias
|
||||
|
||||
```python
|
||||
TIMEZONES = {
|
||||
"central": "America/El_Salvador", # UTC-6
|
||||
"caribbean": "America/Santo_Domingo" # UTC-4
|
||||
}
|
||||
```
|
||||
|
||||
### Notificaciones
|
||||
|
||||
```python
|
||||
WHATSAPP_WEBHOOK = "https://automation.glmanalytics.com/webhook/wsp-notifcation"
|
||||
EMAIL_CONFIG = {
|
||||
"smtp_server": "smtp.gmail.com",
|
||||
"port": 587,
|
||||
"username": "tu_email@gmail.com",
|
||||
"password": "tu_password"
|
||||
}
|
||||
```
|
||||
|
||||
### FTP Global
|
||||
|
||||
```python
|
||||
FTP_CONFIG = {
|
||||
"host": "rcomhost.com",
|
||||
"username": "tu_usuario",
|
||||
"password": "tu_password",
|
||||
"base_path": "/www/TranferData_APP_PYTHON"
|
||||
}
|
||||
```
|
||||
|
||||
## Configuración por Proyecto
|
||||
|
||||
### pgConfig.py
|
||||
|
||||
Configuración específica para Pentagono Group.
|
||||
|
||||
```python
|
||||
class PGConfig:
|
||||
name = "pg"
|
||||
timezone = "central"
|
||||
|
||||
reports = [
|
||||
{"name": "Cobertura", "ftp": True, "sharepoint": True, "n8n": False},
|
||||
{"name": "Checkout", "ftp": True, "sharepoint": False, "n8n": True},
|
||||
# ... más reportes
|
||||
]
|
||||
|
||||
sharepoint_config = {
|
||||
"site_url": "https://pgone.sharepoint.com",
|
||||
"client_id": "tu_client_id",
|
||||
"tenant_id": "tu_tenant_id",
|
||||
"folder_mappings": {
|
||||
"Cobertura": "/sites/PGReports/Cobertura",
|
||||
"Checkout": "/sites/PGReports/Checkout"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### feduroConfig.py
|
||||
|
||||
Configuración para proyecto FEDURO.
|
||||
|
||||
```python
|
||||
class FeduroConfig:
|
||||
name = "feduro"
|
||||
timezone = "caribbean"
|
||||
|
||||
reports = [
|
||||
{"name": "Cobertura", "ftp": False, "sftp": True, "n8n": False},
|
||||
# ... más reportes
|
||||
]
|
||||
|
||||
sftp_config = {
|
||||
"host": "tu-azure-container-instance",
|
||||
"username": "tu_usuario",
|
||||
"password": "tu_password",
|
||||
"port": 22,
|
||||
"path_mappings": {
|
||||
"Cobertura": "/feduro/reports/cobertura",
|
||||
"Checkout": "/feduro/reports/checkout"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Flags de Distribución
|
||||
|
||||
Cada reporte puede configurarse para múltiples destinos:
|
||||
|
||||
- **ftp:** Subida a servidor FTP
|
||||
- **sftp:** Subida a servidor SFTP (Azure)
|
||||
- **sharepoint:** Subida a SharePoint/OneDrive
|
||||
- **n8n:** Trigger de webhook N8N
|
||||
|
||||
## Credenciales Seguras
|
||||
|
||||
### Variables de Entorno (Recomendado)
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
export DB_USER="usuario_seguro"
|
||||
export DB_PASSWORD="password_seguro"
|
||||
export SHAREPOINT_CLIENT_ID="client_id_seguro"
|
||||
|
||||
# Windows
|
||||
set DB_USER=usuario_seguro
|
||||
set DB_PASSWORD=password_seguro
|
||||
```
|
||||
|
||||
### Modificar Código para Usar Variables
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
USERNAME = os.getenv("DB_USER", "default_user")
|
||||
PASSWORD = os.getenv("DB_PASSWORD", "default_password")
|
||||
```
|
||||
|
||||
## Configuración de Docker
|
||||
|
||||
### Dockerfile
|
||||
|
||||
```dockerfile
|
||||
FROM python:3.9-slim
|
||||
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
EXPOSE 5000
|
||||
|
||||
CMD ["python", "main.py"]
|
||||
```
|
||||
|
||||
### docker-compose.yml
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
services:
|
||||
datatransfer:
|
||||
build: .
|
||||
ports:
|
||||
- "5000:5000"
|
||||
environment:
|
||||
- DB_USER=${DB_USER}
|
||||
- DB_PASSWORD=${DB_PASSWORD}
|
||||
volumes:
|
||||
- ./Reportes:/app/Reportes
|
||||
- ./Logs:/app/Logs
|
||||
```
|
||||
|
||||
## Validación de Configuración
|
||||
|
||||
### Verificar Conexiones
|
||||
|
||||
```python
|
||||
# Probar conexión DB
|
||||
from App.Utils.db_utils import DatabaseManager
|
||||
db = DatabaseManager()
|
||||
conn = db.get_connection("pg")
|
||||
# Debería conectar sin errores
|
||||
|
||||
# Probar FTP
|
||||
from App.Utils.ftp_utils import FTPManager
|
||||
ftp = FTPManager()
|
||||
ftp.connect()
|
||||
# Debería conectar sin errores
|
||||
```
|
||||
|
||||
### Validar Reportes
|
||||
|
||||
```python
|
||||
# Verificar que todos los reportes tengan configuraciones válidas
|
||||
for config in [PGConfig, FeduroConfig]:
|
||||
for report in config.reports:
|
||||
assert "name" in report
|
||||
assert any([report.get("ftp"), report.get("sftp"), report.get("sharepoint"), report.get("n8n")])
|
||||
```
|
||||
|
||||
## Configuración de Producción
|
||||
|
||||
### Variables de Entorno
|
||||
|
||||
- `FLASK_ENV=production`
|
||||
- `SECRET_KEY=tu_clave_secreta`
|
||||
- `LOG_LEVEL=INFO`
|
||||
|
||||
### Configuración de Logging
|
||||
|
||||
```python
|
||||
LOGGING_CONFIG = {
|
||||
"version": 1,
|
||||
"formatters": {
|
||||
"detailed": {
|
||||
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
"file": {
|
||||
"class": "logging.FileHandler",
|
||||
"filename": "Logs/app.log",
|
||||
"formatter": "detailed"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"level": "INFO",
|
||||
"handlers": ["file"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Problemas Comunes
|
||||
|
||||
1. **Conexión DB falla:** Verificar credenciales y firewall
|
||||
2. **FTP timeout:** Revisar configuración de red y credenciales
|
||||
3. **SharePoint error:** Validar client_id y permisos en Azure AD
|
||||
4. **SFTP falla:** Confirmar host y puerto de Azure Container Instance
|
||||
|
||||
### Logs de Configuración
|
||||
|
||||
Los errores de configuración se registran en `Logs/etl.log` con mensajes descriptivos.
|
||||
@@ -0,0 +1,307 @@
|
||||
# Despliegue
|
||||
|
||||
## Opciones de Despliegue
|
||||
|
||||
DataTransferV2 puede desplegarse localmente, en contenedores Docker o en la nube.
|
||||
|
||||
## Despliegue Local
|
||||
|
||||
### Requisitos
|
||||
|
||||
- Python 3.8+
|
||||
- SQL Server accesible
|
||||
- Espacio en disco para reportes (~1GB/día)
|
||||
|
||||
### Pasos
|
||||
|
||||
1. **Instalar dependencias**
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
2. **Configurar entorno**
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Editar .env con credenciales
|
||||
```
|
||||
|
||||
3. **Ejecutar**
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
4. **Programar ejecución**
|
||||
```bash
|
||||
# Usando cron (Linux)
|
||||
0 */2 * * * /path/to/env/bin/python /path/to/main.py
|
||||
|
||||
# Usando Task Scheduler (Windows)
|
||||
# Crear tarea programada cada 2 horas
|
||||
```
|
||||
|
||||
## Despliegue con Docker
|
||||
|
||||
### Construir Imagen
|
||||
|
||||
```bash
|
||||
# Desde directorio raíz
|
||||
docker build -t datatransfer:latest .
|
||||
```
|
||||
|
||||
### Ejecutar Contenedor
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name datatransfer \
|
||||
-p 5000:5000 \
|
||||
-v $(pwd)/Reportes:/app/Reportes \
|
||||
-v $(pwd)/Logs:/app/Logs \
|
||||
-e DB_USER=$DB_USER \
|
||||
-e DB_PASSWORD=$DB_PASSWORD \
|
||||
datatransfer:latest
|
||||
```
|
||||
|
||||
### Usando Docker Compose
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
version: '3.8'
|
||||
services:
|
||||
datatransfer:
|
||||
build: .
|
||||
ports:
|
||||
- "5000:5000"
|
||||
environment:
|
||||
- FLASK_ENV=production
|
||||
- DB_USER=${DB_USER}
|
||||
- DB_PASSWORD=${DB_PASSWORD}
|
||||
- SHAREPOINT_CLIENT_ID=${SHAREPOINT_CLIENT_ID}
|
||||
volumes:
|
||||
- ./Reportes:/app/Reportes
|
||||
- ./Logs:/app/Logs
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Despliegue en la Nube
|
||||
|
||||
### Azure Container Instances
|
||||
|
||||
```bash
|
||||
# Construir y subir imagen
|
||||
az acr build --registry myregistry --image datatransfer:latest .
|
||||
|
||||
# Crear container instance
|
||||
az container create \
|
||||
--resource-group myResourceGroup \
|
||||
--name datatransfer \
|
||||
--image myregistry.azurecr.io/datatransfer:latest \
|
||||
--cpu 1 --memory 1.5 \
|
||||
--environment-variables \
|
||||
DB_USER=$DB_USER \
|
||||
DB_PASSWORD=$DB_PASSWORD \
|
||||
--ports 5000 \
|
||||
--restart-policy OnFailure
|
||||
```
|
||||
|
||||
### Azure App Service
|
||||
|
||||
1. **Crear App Service**
|
||||
```bash
|
||||
az appservice plan create --name myPlan --resource-group myRG --sku B1
|
||||
az webapp create --name datatransfer --plan myPlan --resource-group myRG
|
||||
```
|
||||
|
||||
2. **Configurar deployment**
|
||||
```bash
|
||||
az webapp config appsettings set \
|
||||
--name datatransfer \
|
||||
--resource-group myRG \
|
||||
--setting WEBSITES_PORT=5000
|
||||
```
|
||||
|
||||
3. **Deploy con Git**
|
||||
```bash
|
||||
az webapp deployment source config-local-git \
|
||||
--name datatransfer \
|
||||
--resource-group myRG
|
||||
```
|
||||
|
||||
### AWS EC2
|
||||
|
||||
```bash
|
||||
# Instalar Docker en EC2
|
||||
sudo yum update -y
|
||||
sudo amazon-linux-extras install docker
|
||||
sudo service docker start
|
||||
sudo usermod -a -G docker ec2-user
|
||||
|
||||
# Ejecutar contenedor
|
||||
docker run -d -p 5000:5000 \
|
||||
-e DB_USER=$DB_USER \
|
||||
-e DB_PASSWORD=$DB_PASSWORD \
|
||||
datatransfer:latest
|
||||
```
|
||||
|
||||
### Google Cloud Run
|
||||
|
||||
```bash
|
||||
# Construir imagen
|
||||
gcloud builds submit --tag gcr.io/PROJECT-ID/datatransfer
|
||||
|
||||
# Deploy
|
||||
gcloud run deploy datatransfer \
|
||||
--image gcr.io/PROJECT-ID/datatransfer \
|
||||
--platform managed \
|
||||
--port 5000 \
|
||||
--set-env-vars DB_USER=$DB_USER,DB_PASSWORD=$DB_PASSWORD \
|
||||
--allow-unauthenticated
|
||||
```
|
||||
|
||||
## Configuración de Producción
|
||||
|
||||
### Variables de Entorno
|
||||
|
||||
```bash
|
||||
# Base de datos
|
||||
DB_USER=prod_user
|
||||
DB_PASSWORD=prod_password
|
||||
DB_SERVER=prod-sql-server.database.windows.net
|
||||
|
||||
# SharePoint
|
||||
SHAREPOINT_CLIENT_ID=prod_client_id
|
||||
SHAREPOINT_TENANT_ID=prod_tenant_id
|
||||
|
||||
# FTP
|
||||
FTP_HOST=prod-ftp.example.com
|
||||
FTP_USER=prod_ftp_user
|
||||
FTP_PASSWORD=prod_ftp_password
|
||||
|
||||
# Aplicación
|
||||
FLASK_ENV=production
|
||||
SECRET_KEY=your-secret-key-here
|
||||
LOG_LEVEL=INFO
|
||||
```
|
||||
|
||||
### Configuración de Logging
|
||||
|
||||
```python
|
||||
# En GeneralConfig.py
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'formatters': {
|
||||
'verbose': {
|
||||
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
|
||||
'style': '{',
|
||||
},
|
||||
},
|
||||
'handlers': {
|
||||
'file': {
|
||||
'class': 'logging.FileHandler',
|
||||
'filename': 'Logs/production.log',
|
||||
'formatter': 'verbose',
|
||||
},
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'verbose',
|
||||
},
|
||||
},
|
||||
'root': {
|
||||
'handlers': ['console', 'file'],
|
||||
'level': 'INFO',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Monitoreo y Mantenimiento
|
||||
|
||||
### Health Checks
|
||||
|
||||
```python
|
||||
# Endpoint de health check
|
||||
@app.route('/health')
|
||||
def health():
|
||||
# Verificar conexión DB
|
||||
try:
|
||||
db = DatabaseManager()
|
||||
conn = db.get_connection('pg')
|
||||
conn.close()
|
||||
return {'status': 'healthy', 'database': 'ok'}
|
||||
except Exception as e:
|
||||
return {'status': 'unhealthy', 'database': str(e)}, 500
|
||||
```
|
||||
|
||||
### Logs en la Nube
|
||||
|
||||
#### Azure Application Insights
|
||||
|
||||
```python
|
||||
from applicationinsights import TelemetryClient
|
||||
|
||||
tc = TelemetryClient('your-instrumentation-key')
|
||||
tc.track_event('ETL Started')
|
||||
tc.track_metric('Reports Processed', report_count)
|
||||
tc.flush()
|
||||
```
|
||||
|
||||
#### AWS CloudWatch
|
||||
|
||||
```python
|
||||
import boto3
|
||||
|
||||
cloudwatch = boto3.client('cloudwatch')
|
||||
cloudwatch.put_metric_data(
|
||||
Namespace='DataTransfer',
|
||||
MetricData=[
|
||||
{
|
||||
'MetricName': 'ReportsProcessed',
|
||||
'Value': report_count,
|
||||
'Unit': 'Count'
|
||||
}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
### Backup y Recuperación
|
||||
|
||||
- **Reportes:** Los archivos Excel se generan diariamente
|
||||
- **Logs:** Rotar logs semanalmente
|
||||
- **Base de datos:** Backup automático de SQL Server
|
||||
- **Configuración:** Versionar archivos de config en Git
|
||||
|
||||
## Escalado
|
||||
|
||||
### Horizontal Scaling
|
||||
|
||||
- **Múltiples instancias:** Ejecutar múltiples contenedores
|
||||
- **Load balancer:** Distribuir requests entre instancias
|
||||
- **Queue system:** Usar Redis/RabbitMQ para jobs ETL
|
||||
|
||||
### Vertical Scaling
|
||||
|
||||
- **CPU/Memoria:** Aumentar recursos del contenedor
|
||||
- **Database:** Usar réplicas de lectura para consultas API
|
||||
|
||||
## Seguridad en Producción
|
||||
|
||||
### Red
|
||||
|
||||
- **Firewall:** Restringir acceso solo a IPs necesarias
|
||||
- **VPC:** Aislar en red privada
|
||||
- **HTTPS:** Usar certificados SSL
|
||||
|
||||
### Autenticación
|
||||
|
||||
- **API Keys:** Para acceso a API
|
||||
- **OAuth:** Para UI web
|
||||
- **Secrets Management:** Azure Key Vault, AWS Secrets Manager
|
||||
|
||||
### Actualizaciones
|
||||
|
||||
- **Zero-downtime:** Usar blue-green deployment
|
||||
- **Rollback:** Mantener versiones anteriores
|
||||
- **Testing:** Probar en staging antes de producción
|
||||
@@ -0,0 +1,301 @@
|
||||
# Flujo de Datos
|
||||
|
||||
## Pipeline ETL General
|
||||
|
||||
DataTransferV2 sigue un patrón ETL clásico con etapas bien definidas y manejo de errores resiliente.
|
||||
|
||||
```
|
||||
EXTRACT → TRANSFORM → LOAD → NOTIFY
|
||||
```
|
||||
|
||||
## Diagrama de Flujo
|
||||
|
||||
```
|
||||
Inicio
|
||||
↓
|
||||
Cargar Configuraciones (PG, FEDURO)
|
||||
↓
|
||||
Para cada Proyecto:
|
||||
┌─────────────────────────────────────┐
|
||||
│ Para cada Reporte: │
|
||||
│ Para cada Fecha (3 días): │
|
||||
│ ┌─────────────────────────────┐ │
|
||||
│ │ EJECUTAR ETL │ │
|
||||
│ │ ┌─────────┐ ┌──────────┐ │ │
|
||||
│ │ │ EXTRACT │→ │TRANSFORM│ │ │
|
||||
│ │ └─────────┘ └──────────┘ │ │
|
||||
│ │ ↓ │ │
|
||||
│ │ ┌─────────┐ │ │
|
||||
│ │ │ LOAD │ │ │
|
||||
│ │ └─────────┘ │ │
|
||||
│ └─────────────────────────────┘ │
|
||||
└─────────────────────────────────────┘
|
||||
↓
|
||||
Agregar Resultados
|
||||
↓
|
||||
Enviar Notificación
|
||||
↓
|
||||
Fin
|
||||
```
|
||||
|
||||
## Etapa EXTRACT
|
||||
|
||||
### Proceso
|
||||
|
||||
1. **Conectar a Base de Datos**
|
||||
- Usar pyodbc para conexión SQL Server
|
||||
- Pooling de conexiones para eficiencia
|
||||
|
||||
2. **Construir Query**
|
||||
```sql
|
||||
SELECT * FROM {TableName} WHERE Fecha = '{YYYY-MM-DD}'
|
||||
```
|
||||
|
||||
3. **Ejecutar Consulta**
|
||||
- Timeout de 30 segundos
|
||||
- Manejo de excepciones de conexión
|
||||
|
||||
4. **Validar Resultados**
|
||||
- Contar registros obtenidos
|
||||
- Verificar integridad de datos
|
||||
|
||||
### Estados Posibles
|
||||
|
||||
- **SUCCESS:** Datos encontrados (>0 registros)
|
||||
- **WARNING:** Sin datos (=0 registros)
|
||||
- **FAILED:** Error de conexión/query
|
||||
|
||||
## Etapa TRANSFORM
|
||||
|
||||
### Proceso
|
||||
|
||||
1. **Crear DataFrame**
|
||||
- Usar pandas para manipulación de datos
|
||||
- Validar tipos de datos
|
||||
|
||||
2. **Generar Excel**
|
||||
- Usar openpyxl para formato Excel
|
||||
- Crear hoja única con datos tabulares
|
||||
- Aplicar formato básico (headers en negrita)
|
||||
|
||||
3. **Guardar Archivo**
|
||||
```
|
||||
Reportes/{PROJECT}/{REPORT}/{REPORT}-{YYYYMMDD}.xlsx
|
||||
```
|
||||
|
||||
4. **Validar Archivo**
|
||||
- Verificar que se creó correctamente
|
||||
- Comprobar tamaño del archivo
|
||||
|
||||
### Formato de Salida
|
||||
|
||||
- **Nombre:** `{Reporte}-{Fecha}.xlsx`
|
||||
- **Estructura:** Hoja única con headers
|
||||
- **Encoding:** UTF-8
|
||||
- **Separador:** Sin separador (datos crudos)
|
||||
|
||||
## Etapa LOAD
|
||||
|
||||
### Destinos Múltiples
|
||||
|
||||
Cada reporte puede distribuirse a múltiples destinos según flags de configuración.
|
||||
|
||||
#### FTP Upload
|
||||
|
||||
1. **Conectar al Servidor**
|
||||
```python
|
||||
ftp = FTP(host, user, password)
|
||||
```
|
||||
|
||||
2. **Crear Directorios**
|
||||
```
|
||||
/TranferData_APP_PYTHON/{PROJECT}/{REPORT}/
|
||||
```
|
||||
|
||||
3. **Subir Archivo**
|
||||
- Batch de 100 archivos
|
||||
- Reintentos automáticos en caso de fallo
|
||||
|
||||
4. **Verificar Upload**
|
||||
- Comparar tamaños local/remoto
|
||||
|
||||
#### SFTP Upload (FEDURO)
|
||||
|
||||
1. **Conectar via SSH**
|
||||
```python
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.connect(host, username, password)
|
||||
sftp = ssh.open_sftp()
|
||||
```
|
||||
|
||||
2. **Navegar a Directorio**
|
||||
- Mapeo específico por reporte en `feduroConfig.py`
|
||||
|
||||
3. **Subir Archivo**
|
||||
- Transferencia segura
|
||||
- Verificación de integridad
|
||||
|
||||
#### SharePoint Upload (PG)
|
||||
|
||||
1. **Autenticar con Office365**
|
||||
```python
|
||||
ctx = ClientContext(site_url).with_credentials(credentials)
|
||||
```
|
||||
|
||||
2. **Subir a Document Library**
|
||||
- Mapeo de carpetas por reporte
|
||||
- Sobrescribir archivos existentes
|
||||
|
||||
3. **Verificar Upload**
|
||||
- Confirmar presencia en SharePoint
|
||||
|
||||
#### N8N Webhook
|
||||
|
||||
1. **Construir Payload**
|
||||
```json
|
||||
{
|
||||
"project": "pg",
|
||||
"report": "Cobertura",
|
||||
"date": "2024-01-15",
|
||||
"file_path": "/path/to/file.xlsx"
|
||||
}
|
||||
```
|
||||
|
||||
2. **Enviar POST Request**
|
||||
- Trigger automatización N8N
|
||||
- No espera respuesta
|
||||
|
||||
### Estrategia de Distribución
|
||||
|
||||
- **Paralelo:** Todos los destinos se procesan simultáneamente
|
||||
- **Resiliente:** Fallo en un destino no afecta otros
|
||||
- **Logging:** Cada upload se registra individualmente
|
||||
|
||||
## Agregación de Resultados
|
||||
|
||||
### Reglas de Negocio
|
||||
|
||||
1. **Éxito (SUCCESS)**
|
||||
- Datos encontrados, Excel creado, todos los uploads exitosos
|
||||
|
||||
2. **Completado con Errores (COMPLETED_WITH_ERRORS)**
|
||||
- Datos procesados, pero algunos uploads fallaron
|
||||
- No bloquea el pipeline
|
||||
|
||||
3. **Advertencia (WARNING)**
|
||||
- Sin datos para la fecha
|
||||
- Ignorado si es domingo
|
||||
|
||||
4. **Fallo (FAILED)**
|
||||
- Error en consulta DB o creación de Excel
|
||||
- Detiene procesamiento del reporte
|
||||
|
||||
### Lógica de Consolidación
|
||||
|
||||
```python
|
||||
# Reglas de negocio para warnings
|
||||
if consecutive_warnings >= 3:
|
||||
status = "FAILED"
|
||||
elif is_sunday and no_data:
|
||||
status = "IGNORED"
|
||||
elif no_data:
|
||||
status = "WARNING"
|
||||
else:
|
||||
status = "SUCCESS"
|
||||
```
|
||||
|
||||
## Notificaciones
|
||||
|
||||
### WhatsApp Summary
|
||||
|
||||
Después de completar cada proyecto:
|
||||
|
||||
```
|
||||
✅ PG - Completado
|
||||
Total: 16, Éxito: 15, Errores: 1, Advertencias: 0
|
||||
Tiempo de ejecución: 45 minutos
|
||||
Detalles de errores: Cobertura-2024-01-15 (FTP timeout)
|
||||
```
|
||||
|
||||
### Contenido del Mensaje
|
||||
|
||||
- **Estado del proyecto:** ✅ ⚠️ ❌
|
||||
- **Estadísticas:** Total, éxito, errores, advertencias
|
||||
- **Tiempo:** Duración total
|
||||
- **Errores específicos:** Lista de reportes/fechas con problemas
|
||||
|
||||
## Manejo de Errores
|
||||
|
||||
### Tipos de Error
|
||||
|
||||
1. **Errores de Conexión**
|
||||
- DB: Reintentar conexión
|
||||
- FTP/SFTP: Reintentar upload
|
||||
- SharePoint: Reautenticar
|
||||
|
||||
2. **Errores de Datos**
|
||||
- Sin datos: Advertencia (no error)
|
||||
- Datos corruptos: Fallo crítico
|
||||
|
||||
3. **Errores de Sistema**
|
||||
- Disco lleno: Fallo crítico
|
||||
- Memoria insuficiente: Reinicio automático
|
||||
|
||||
### Recuperación
|
||||
|
||||
- **Reintentos:** Hasta 3 intentos para operaciones de red
|
||||
- **Fallback:** Continuar con otros destinos si uno falla
|
||||
- **Logging:** Todos los errores se registran con contexto completo
|
||||
|
||||
## Rendimiento
|
||||
|
||||
### Métricas Típicas
|
||||
|
||||
- **Tiempo por reporte:** 30-120 segundos
|
||||
- **Throughput:** 16-18 reportes por proyecto (~30-60 min)
|
||||
- **Uso de memoria:** 100-500MB por ejecución
|
||||
- **I/O:** 10-50MB por reporte Excel
|
||||
|
||||
### Optimizaciones
|
||||
|
||||
- **Conexiones pool:** Reutilización de conexiones DB
|
||||
- **Procesamiento por lotes:** Múltiples fechas en una ejecución
|
||||
- **Compresión:** Archivos Excel optimizados
|
||||
- **Paralelización:** Uploads simultáneos
|
||||
|
||||
## Auditoría
|
||||
|
||||
### Logging a Base de Datos
|
||||
|
||||
Cada ejecución se registra en `ExecutionLog`:
|
||||
|
||||
```sql
|
||||
INSERT INTO ExecutionLog (
|
||||
ProcedureID, Name, Status, Message,
|
||||
StartTime, EndTime, Duration
|
||||
) VALUES (
|
||||
1001, 'Cobertura', 'SUCCESS', 'Processed 1500 records',
|
||||
'2024-01-15 08:00:00', '2024-01-15 08:02:30', 150
|
||||
)
|
||||
```
|
||||
|
||||
### Logs de Aplicación
|
||||
|
||||
- `Logs/etl.log`: Progreso detallado
|
||||
- `Logs/api.log`: Requests API
|
||||
- `Logs/reports.log`: Generación de reportes
|
||||
|
||||
## Monitoreo
|
||||
|
||||
### KPIs Principales
|
||||
|
||||
- **Tasa de éxito:** % de reportes procesados correctamente
|
||||
- **Tiempo promedio:** Duración por reporte/proyecto
|
||||
- **Errores por tipo:** DB, red, sistema
|
||||
- **Volumen de datos:** Registros/filas procesadas
|
||||
|
||||
### Alertas
|
||||
|
||||
- Error rate > 10%
|
||||
- Duración > 2x promedio
|
||||
- Fallos consecutivos en mismo reporte
|
||||
@@ -0,0 +1,21 @@
|
||||
# Índice de Documentación
|
||||
|
||||
Bienvenido a la documentación de **DataTransferV2**, una aplicación ETL automatizada para transferencias de datos.
|
||||
|
||||
## Archivos de Documentación
|
||||
|
||||
- **[Arquitectura.md](Arquitectura.md)**: Descripción de la arquitectura general, componentes y tecnologías utilizadas.
|
||||
- **[Instalacion.md](Instalacion.md)**: Guía paso a paso para instalar y configurar el proyecto.
|
||||
- **[Uso.md](Uso.md)**: Instrucciones para usar la aplicación, incluyendo ejecución automática, interfaz web y API.
|
||||
- **[API.md](API.md)**: Referencia completa de la API REST para descargas de datos.
|
||||
- **[Configuracion.md](Configuracion.md)**: Detalles sobre la configuración de proyectos, bases de datos y destinos.
|
||||
- **[Despliegue.md](Despliegue.md)**: Guías para desplegar la aplicación en producción usando Docker.
|
||||
- **[Flujo_de_Datos.md](Flujo_de_Datos.md)**: Explicación del pipeline ETL y flujo de datos.
|
||||
- **[Manejo_de_Errores.md](Manejo_de_Errores.md)**: Información sobre clasificación de errores, reglas de negocio y logging.
|
||||
- **[Seguridad.md](Seguridad.md)**: Notas sobre seguridad, credenciales y mejores prácticas.
|
||||
|
||||
## Acerca del Proyecto
|
||||
|
||||
DataTransferV2 es un sistema ETL que extrae datos de SQL Server, genera reportes Excel y los distribuye a múltiples plataformas. Incluye UI web y API para operaciones manuales.
|
||||
|
||||
Para más información, consulta el [README.md](../README.md) en la raíz del proyecto.
|
||||
@@ -0,0 +1,110 @@
|
||||
# Instalación
|
||||
|
||||
## Prerrequisitos
|
||||
|
||||
- **Python:** Versión 3.8 o superior
|
||||
- **Base de Datos:** SQL Server con bases de datos configuradas (glm_pg, IS001)
|
||||
- **Sistema Operativo:** Windows, Linux o macOS
|
||||
- **Docker:** Opcional, para contenedorización
|
||||
|
||||
## Instalación Local
|
||||
|
||||
### 1. Clonar el Repositorio
|
||||
|
||||
```bash
|
||||
git clone <url-del-repositorio>
|
||||
cd DataTransferV2
|
||||
```
|
||||
|
||||
### 2. Crear Entorno Virtual
|
||||
|
||||
```bash
|
||||
# Windows
|
||||
python -m venv env
|
||||
env\Scripts\activate
|
||||
|
||||
# Linux/macOS
|
||||
python3 -m venv env
|
||||
source env/bin/activate
|
||||
```
|
||||
|
||||
### 3. Instalar Dependencias
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 4. Configurar la Base de Datos
|
||||
|
||||
Asegúrate de que SQL Server esté ejecutándose y accesible. Las bases de datos requeridas:
|
||||
- `glm_pg` (ID: 00080001)
|
||||
- `IS001` (ID: 00010007)
|
||||
- Servidor: sql.glmanalytics.com
|
||||
|
||||
### 5. Configurar Credenciales
|
||||
|
||||
Edita `App/Config/GeneralConfig.py` con:
|
||||
- Credenciales de SQL Server
|
||||
- Endpoints FTP/SFTP/SharePoint
|
||||
- URLs de webhooks para notificaciones
|
||||
|
||||
### 6. Verificar Instalación
|
||||
|
||||
```bash
|
||||
python main.py --help # Si tiene opción help
|
||||
```
|
||||
|
||||
## Instalación con Docker
|
||||
|
||||
### Construir Imagen
|
||||
|
||||
```bash
|
||||
docker build -t datatransfer .
|
||||
```
|
||||
|
||||
### Ejecutar Contenedor
|
||||
|
||||
```bash
|
||||
docker run -p 5000:5000 datatransfer
|
||||
```
|
||||
|
||||
### Usando Docker Compose
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Configuración de Entorno
|
||||
|
||||
### Variables de Entorno (Recomendado)
|
||||
|
||||
Para mayor seguridad, usa variables de entorno en lugar de hardcodear credenciales:
|
||||
|
||||
```bash
|
||||
export DB_USER="tu_usuario"
|
||||
export DB_PASSWORD="tu_password"
|
||||
export SHAREPOINT_CLIENT_ID="tu_client_id"
|
||||
```
|
||||
|
||||
### Configuración de Zonas Horarias
|
||||
|
||||
El sistema maneja zonas horarias de Centroamérica y el Caribe. Asegúrate de que el servidor esté en la zona correcta.
|
||||
|
||||
## Solución de Problemas
|
||||
|
||||
### Error de Conexión DB
|
||||
- Verifica credenciales en GeneralConfig.py
|
||||
- Confirma que SQL Server esté ejecutándose
|
||||
- Revisa firewall y permisos de red
|
||||
|
||||
### Dependencias Faltantes
|
||||
- Asegúrate de tener pip actualizado: `pip install --upgrade pip`
|
||||
- Instala dependencias específicas: `pip install pyodbc azure-storage-blob`
|
||||
|
||||
### Problemas con SharePoint
|
||||
- Verifica client_id y tenant_id
|
||||
- Confirma permisos de aplicación en Azure AD
|
||||
|
||||
## Próximos Pasos
|
||||
|
||||
Después de la instalación, configura los proyectos específicos y ejecuta una prueba con `python main.py`.
|
||||
@@ -0,0 +1,372 @@
|
||||
# Manejo de Errores
|
||||
|
||||
## Clasificación de Errores
|
||||
|
||||
DataTransferV2 clasifica los errores en tres categorías principales con diferentes impactos en el pipeline.
|
||||
|
||||
## Estados de Ejecución
|
||||
|
||||
### SUCCESS (✅)
|
||||
**Definición:** Ejecución completamente exitosa
|
||||
**Condiciones:**
|
||||
- Datos encontrados en base de datos
|
||||
- Archivo Excel generado correctamente
|
||||
- Todos los destinos de distribución exitosos
|
||||
|
||||
**Ejemplo:**
|
||||
```
|
||||
✅ Cobertura-2024-01-15: 1,500 registros procesados, FTP+SharePoint OK
|
||||
```
|
||||
|
||||
### COMPLETED_WITH_ERRORS (⚠️)
|
||||
**Definición:** Datos procesados pero con fallos en distribución
|
||||
**Condiciones:**
|
||||
- Datos encontrados y Excel generado
|
||||
- Al menos un destino de distribución falló
|
||||
- Otros destinos pueden haber sido exitosos
|
||||
|
||||
**Impacto:** No detiene el pipeline, continúa con siguientes reportes
|
||||
|
||||
**Ejemplo:**
|
||||
```
|
||||
⚠️ Checkout-2024-01-15: Datos OK, FTP falló (timeout), SharePoint OK
|
||||
```
|
||||
|
||||
### WARNING (ℹ️)
|
||||
**Definición:** Sin datos disponibles
|
||||
**Condiciones:**
|
||||
- Query ejecutada correctamente
|
||||
- 0 registros retornados
|
||||
- No se genera archivo Excel
|
||||
|
||||
**Reglas de negocio:**
|
||||
- Si es domingo + sin datos → Ignorado
|
||||
- 3+ warnings consecutivos → Se eleva a FAILED
|
||||
|
||||
**Ejemplo:**
|
||||
```
|
||||
ℹ️ Promociones-2024-01-15: Sin datos disponibles
|
||||
```
|
||||
|
||||
### FAILED (❌)
|
||||
**Definición:** Fallo crítico que detiene el procesamiento
|
||||
**Condiciones:**
|
||||
- Error en conexión a base de datos
|
||||
- Error en query SQL
|
||||
- Error en generación de Excel
|
||||
- 3+ warnings consecutivos en mismo reporte
|
||||
|
||||
**Impacto:** Detiene procesamiento del reporte actual
|
||||
|
||||
**Ejemplo:**
|
||||
```
|
||||
❌ QualityDisplay-2024-01-15: Error de conexión DB - timeout
|
||||
```
|
||||
|
||||
## Tipos de Errores Técnicos
|
||||
|
||||
### Errores de Base de Datos
|
||||
|
||||
#### Connection Timeout
|
||||
```
|
||||
Error: [08001] [Microsoft][ODBC SQL Server Driver]Timeout expired
|
||||
Causa: Red lenta, servidor sobrecargado
|
||||
Solución: Reintentar, verificar conectividad
|
||||
```
|
||||
|
||||
#### Authentication Failed
|
||||
```
|
||||
Error: [28000] [Microsoft][ODBC SQL Server Driver]Login failed
|
||||
Causa: Credenciales incorrectas
|
||||
Solución: Verificar USERNAME/PASSWORD en config
|
||||
```
|
||||
|
||||
#### Database Not Found
|
||||
```
|
||||
Error: [08004] [Microsoft][ODBC SQL Server Driver]Server does not exist
|
||||
Causa: Servidor incorrecto o no accesible
|
||||
Solución: Verificar SERVER en config
|
||||
```
|
||||
|
||||
#### Query Syntax Error
|
||||
```
|
||||
Error: [42000] [Microsoft][ODBC SQL Server Driver]Incorrect syntax
|
||||
Causa: Nombre de tabla/columna incorrecto
|
||||
Solución: Verificar configuración de reportes
|
||||
```
|
||||
|
||||
### Errores de FTP
|
||||
|
||||
#### Connection Failed
|
||||
```
|
||||
Error: [Errno 110] Connection timed out
|
||||
Causa: Firewall, red bloqueada
|
||||
Solución: Verificar host/puerto, permisos de red
|
||||
```
|
||||
|
||||
#### Authentication Failed
|
||||
```
|
||||
Error: 530 Login incorrect
|
||||
Causa: Credenciales FTP incorrectas
|
||||
Solución: Verificar FTP_CONFIG
|
||||
```
|
||||
|
||||
#### Permission Denied
|
||||
```
|
||||
Error: 550 Permission denied
|
||||
Causa: Usuario sin permisos de escritura
|
||||
Solución: Verificar permisos en servidor FTP
|
||||
```
|
||||
|
||||
#### Disk Full
|
||||
```
|
||||
Error: 452 Insufficient storage space
|
||||
Causa: Espacio insuficiente en servidor
|
||||
Solución: Liberar espacio, contactar administrador
|
||||
```
|
||||
|
||||
### Errores de SFTP
|
||||
|
||||
#### SSH Connection Failed
|
||||
```
|
||||
Error: [Errno 61] Connection refused
|
||||
Causa: Puerto cerrado, servidor no responde
|
||||
Solución: Verificar host/puerto SFTP
|
||||
```
|
||||
|
||||
#### Host Key Verification
|
||||
```
|
||||
Error: Host key verification failed
|
||||
Causa: Primera conexión, clave host no conocida
|
||||
Solución: Agregar host a known_hosts o usar policy
|
||||
```
|
||||
|
||||
#### File Transfer Error
|
||||
```
|
||||
Error: Permission denied (publickey,password)
|
||||
Causa: Autenticación fallida
|
||||
Solución: Verificar credenciales SFTP
|
||||
```
|
||||
|
||||
### Errores de SharePoint
|
||||
|
||||
#### Authentication Failed
|
||||
```
|
||||
Error: Invalid client credentials
|
||||
Causa: client_id/tenant_id incorrectos
|
||||
Solución: Verificar configuración Azure AD
|
||||
```
|
||||
|
||||
#### Permission Denied
|
||||
```
|
||||
Error: Access denied
|
||||
Causa: Usuario sin permisos en site/library
|
||||
Solución: Verificar permisos en SharePoint
|
||||
```
|
||||
|
||||
#### File Upload Failed
|
||||
```
|
||||
Error: The file exists
|
||||
Causa: Archivo ya existe, no se puede sobrescribir
|
||||
Solución: Verificar configuración de sobrescritura
|
||||
```
|
||||
|
||||
### Errores de Sistema
|
||||
|
||||
#### Disk Full
|
||||
```
|
||||
Error: [Errno 28] No space left on device
|
||||
Causa: Disco local lleno
|
||||
Solución: Liberar espacio, verificar partición
|
||||
```
|
||||
|
||||
#### Memory Error
|
||||
```
|
||||
Error: MemoryError
|
||||
Causa: DataFrame muy grande
|
||||
Solución: Optimizar query, procesar en lotes
|
||||
```
|
||||
|
||||
#### Encoding Error
|
||||
```
|
||||
Error: 'utf-8' codec can't decode byte
|
||||
Causa: Datos con caracteres especiales
|
||||
Solución: Especificar encoding correcto
|
||||
```
|
||||
|
||||
## Estrategias de Recuperación
|
||||
|
||||
### Reintentos Automáticos
|
||||
|
||||
```python
|
||||
def retry_operation(operation, max_retries=3, delay=5):
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return operation()
|
||||
except Exception as e:
|
||||
if attempt < max_retries - 1:
|
||||
time.sleep(delay * (attempt + 1)) # Backoff exponencial
|
||||
else:
|
||||
raise e
|
||||
```
|
||||
|
||||
**Aplicado a:**
|
||||
- Conexiones de red (FTP, SFTP, SharePoint)
|
||||
- Queries de base de datos
|
||||
- Uploads de archivos
|
||||
|
||||
### Fallback Strategies
|
||||
|
||||
1. **Múltiples Destinos:** Si FTP falla, intentar SFTP
|
||||
2. **Modo Degradado:** Continuar sin notificaciones si webhook falla
|
||||
3. **Cache Local:** Guardar archivos localmente si uploads fallan
|
||||
|
||||
### Circuit Breaker
|
||||
|
||||
```python
|
||||
class CircuitBreaker:
|
||||
def __init__(self, failure_threshold=5, recovery_timeout=300):
|
||||
self.failure_count = 0
|
||||
self.last_failure_time = None
|
||||
self.state = 'CLOSED' # CLOSED, OPEN, HALF_OPEN
|
||||
|
||||
def call(self, func):
|
||||
if self.state == 'OPEN':
|
||||
if time.time() - self.last_failure_time > self.recovery_timeout:
|
||||
self.state = 'HALF_OPEN'
|
||||
else:
|
||||
raise CircuitBreakerError("Circuit is OPEN")
|
||||
|
||||
try:
|
||||
result = func()
|
||||
self._on_success()
|
||||
return result
|
||||
except Exception as e:
|
||||
self._on_failure()
|
||||
raise e
|
||||
```
|
||||
|
||||
## Logging y Monitoreo
|
||||
|
||||
### Niveles de Log
|
||||
|
||||
- **DEBUG:** Detalles técnicos, queries ejecutadas
|
||||
- **INFO:** Progreso normal, estadísticas
|
||||
- **WARNING:** Situaciones no críticas
|
||||
- **ERROR:** Errores que requieren atención
|
||||
- **CRITICAL:** Errores que detienen el sistema
|
||||
|
||||
### Formato de Logs
|
||||
|
||||
```
|
||||
2024-01-15 08:30:15,123 - ETL - INFO - Starting ETL for PG project
|
||||
2024-01-15 08:30:16,456 - DB - DEBUG - Executing query: SELECT * FROM Cobertura WHERE Fecha = '2024-01-15'
|
||||
2024-01-15 08:30:18,789 - REPORT - INFO - Generated Excel: Reportes/PG/Cobertura/Cobertura-20240115.xlsx
|
||||
2024-01-15 08:30:20,012 - FTP - ERROR - Upload failed: Connection timeout
|
||||
2024-01-15 08:30:25,345 - FTP - INFO - Retry 1/3 successful
|
||||
```
|
||||
|
||||
### Base de Datos de Auditoría
|
||||
|
||||
Cada error se registra en `ExecutionLog`:
|
||||
|
||||
```sql
|
||||
INSERT INTO ExecutionLog (
|
||||
ProcedureID, StartTime, EndTime, Status,
|
||||
ErrorType, ErrorMessage, RetryCount
|
||||
) VALUES (
|
||||
1001, '2024-01-15 08:30:15', '2024-01-15 08:30:25', 'COMPLETED_WITH_ERRORS',
|
||||
'FTP_TIMEOUT', 'Connection timed out after 30s', 1
|
||||
)
|
||||
```
|
||||
|
||||
## Alertas y Notificaciones
|
||||
|
||||
### Umbrales de Alerta
|
||||
|
||||
- **Error Rate > 10%:** Notificación inmediata
|
||||
- **3+ fallos consecutivos:** Alerta crítica
|
||||
- **Tiempo de ejecución > 2x promedio:** Warning
|
||||
- **Disco > 90% usado:** Alerta de capacidad
|
||||
|
||||
### Canales de Notificación
|
||||
|
||||
1. **WhatsApp:** Resúmenes diarios
|
||||
2. **Email:** Alertas críticas
|
||||
3. **Logs:** Registro detallado
|
||||
4. **Dashboard:** Métricas en tiempo real (futuro)
|
||||
|
||||
## Debugging
|
||||
|
||||
### Herramientas de Diagnóstico
|
||||
|
||||
#### Verificar Conectividad
|
||||
|
||||
```bash
|
||||
# Base de datos
|
||||
sqlcmd -S sql.glmanalytics.com -U $USERNAME -P $PASSWORD -Q "SELECT 1"
|
||||
|
||||
# FTP
|
||||
ftp $FTP_HOST
|
||||
|
||||
# SFTP
|
||||
sftp $SFTP_USER@$SFTP_HOST
|
||||
```
|
||||
|
||||
#### Analizar Logs
|
||||
|
||||
```bash
|
||||
# Últimos errores
|
||||
tail -f Logs/etl.log | grep ERROR
|
||||
|
||||
# Errores por tipo
|
||||
grep "ERROR" Logs/etl.log | cut -d' ' -f4 | sort | uniq -c
|
||||
```
|
||||
|
||||
#### Probar Componentes Individualmente
|
||||
|
||||
```python
|
||||
# Probar DB
|
||||
from App.Utils.db_utils import DatabaseManager
|
||||
db = DatabaseManager()
|
||||
data = db.execute_query("SELECT TOP 1 * FROM Cobertura")
|
||||
|
||||
# Probar FTP
|
||||
from App.Utils.ftp_utils import FTPManager
|
||||
ftp = FTPManager()
|
||||
ftp.test_connection()
|
||||
```
|
||||
|
||||
### Checklist de Troubleshooting
|
||||
|
||||
- [ ] Credenciales correctas en config
|
||||
- [ ] Servidores accesibles (ping, telnet)
|
||||
- [ ] Puertos abiertos (1433 DB, 21 FTP, 22 SFTP, 443 HTTPS)
|
||||
- [ ] Espacio en disco suficiente
|
||||
- [ ] Permisos de archivo correctos
|
||||
- [ ] Dependencias Python instaladas
|
||||
- [ ] Zona horaria correcta
|
||||
- [ ] Configuración de reportes válida
|
||||
|
||||
## Mejores Prácticas
|
||||
|
||||
### Prevención
|
||||
|
||||
1. **Validación de Configuración:** Verificar al inicio
|
||||
2. **Health Checks:** Monitorear componentes críticos
|
||||
3. **Backup:** Mantener copias de configuraciones
|
||||
4. **Versionado:** Control de cambios en config
|
||||
|
||||
### Respuesta
|
||||
|
||||
1. **Documentar Incidentes:** Registrar causa y resolución
|
||||
2. **Automatizar Recuperación:** Scripts para reintentos
|
||||
3. **Escalada:** Definir cuándo notificar a equipo
|
||||
4. **Post-mortem:** Análisis después de incidentes críticos
|
||||
|
||||
### Mejora Continua
|
||||
|
||||
1. **Métricas:** Recopilar estadísticas de errores
|
||||
2. **Análisis de Tendencias:** Identificar patrones
|
||||
3. **Optimización:** Reducir puntos de fallo
|
||||
4. **Testing:** Cobertura de escenarios de error
|
||||
@@ -0,0 +1,356 @@
|
||||
# Seguridad
|
||||
|
||||
## Principios de Seguridad
|
||||
|
||||
DataTransferV2 maneja datos sensibles y requiere medidas de seguridad apropiadas para entornos de producción.
|
||||
|
||||
## Gestión de Credenciales
|
||||
|
||||
### Problema Actual
|
||||
|
||||
**Las credenciales están hardcodeadas en archivos de configuración:**
|
||||
|
||||
```python
|
||||
# App/Config/GeneralConfig.py
|
||||
USERNAME = "usuario_db"
|
||||
PASSWORD = "password_db"
|
||||
SHAREPOINT_CLIENT_ID = "client_id"
|
||||
```
|
||||
|
||||
### Soluciones Recomendadas
|
||||
|
||||
#### 1. Variables de Entorno
|
||||
|
||||
```bash
|
||||
# Archivo .env
|
||||
DB_USER=usuario_seguro
|
||||
DB_PASSWORD=password_seguro
|
||||
SHAREPOINT_CLIENT_ID=client_id_seguro
|
||||
FTP_PASSWORD=password_ftp_seguro
|
||||
```
|
||||
|
||||
```python
|
||||
# En GeneralConfig.py
|
||||
import os
|
||||
|
||||
USERNAME = os.getenv("DB_USER")
|
||||
PASSWORD = os.getenv("DB_PASSWORD")
|
||||
SHAREPOINT_CLIENT_ID = os.getenv("SHAREPOINT_CLIENT_ID")
|
||||
```
|
||||
|
||||
#### 2. Secrets Management
|
||||
|
||||
##### Azure Key Vault
|
||||
|
||||
```python
|
||||
from azure.keyvault.secrets import SecretClient
|
||||
from azure.identity import DefaultAzureCredential
|
||||
|
||||
credential = DefaultAzureCredential()
|
||||
client = SecretClient(vault_url="https://myvault.vault.azure.net/", credential=credential)
|
||||
|
||||
DB_PASSWORD = client.get_secret("db-password").value
|
||||
```
|
||||
|
||||
##### AWS Secrets Manager
|
||||
|
||||
```python
|
||||
import boto3
|
||||
|
||||
client = boto3.client('secretsmanager')
|
||||
response = client.get_secret_value(SecretId='prod/datatransfer/db')
|
||||
credentials = json.loads(response['SecretString'])
|
||||
DB_USER = credentials['username']
|
||||
DB_PASSWORD = credentials['password']
|
||||
```
|
||||
|
||||
##### HashiCorp Vault
|
||||
|
||||
```python
|
||||
import hvac
|
||||
|
||||
client = hvac.Client(url='https://vault.example.com:8200')
|
||||
client.auth.approle.login(role_id='role_id', secret_id='secret_id')
|
||||
|
||||
DB_PASSWORD = client.read('secret/datatransfer/db')['data']['password']
|
||||
```
|
||||
|
||||
## Autenticación y Autorización
|
||||
|
||||
### API Security
|
||||
|
||||
#### Implementar API Keys
|
||||
|
||||
```python
|
||||
from flask import request, abort
|
||||
|
||||
API_KEYS = os.getenv("API_KEYS", "").split(",")
|
||||
|
||||
def require_api_key(func):
|
||||
@wraps(func)
|
||||
def decorated(*args, **kwargs):
|
||||
api_key = request.headers.get('X-API-Key')
|
||||
if api_key not in API_KEYS:
|
||||
abort(401, "Invalid API key")
|
||||
return func(*args, **kwargs)
|
||||
return decorated
|
||||
|
||||
@app.route('/api/download')
|
||||
@require_api_key
|
||||
def download_data():
|
||||
# Endpoint protegido
|
||||
```
|
||||
|
||||
#### JWT Tokens
|
||||
|
||||
```python
|
||||
from flask_jwt_extended import JWTManager, jwt_required
|
||||
|
||||
app.config['JWT_SECRET_KEY'] = os.getenv('JWT_SECRET_KEY')
|
||||
jwt = JWTManager(app)
|
||||
|
||||
@app.route('/api/download')
|
||||
@jwt_required()
|
||||
def download_data():
|
||||
# Requiere token JWT válido
|
||||
```
|
||||
|
||||
### UI Web Security
|
||||
|
||||
#### Autenticación de Usuario
|
||||
|
||||
```python
|
||||
from flask_login import LoginManager, login_required
|
||||
|
||||
login_manager = LoginManager()
|
||||
login_manager.init_app(app)
|
||||
|
||||
@app.route('/etl')
|
||||
@login_required
|
||||
def etl_interface():
|
||||
# Solo usuarios autenticados
|
||||
```
|
||||
|
||||
#### Rate Limiting
|
||||
|
||||
```python
|
||||
from flask_limiter import Limiter
|
||||
|
||||
limiter = Limiter(app, key_func=lambda: request.remote_addr)
|
||||
|
||||
@app.route('/api/download')
|
||||
@limiter.limit("10 per minute")
|
||||
def download_data():
|
||||
# Máximo 10 requests por minuto por IP
|
||||
```
|
||||
|
||||
## Encriptación de Datos
|
||||
|
||||
### En Tránsito
|
||||
|
||||
#### HTTPS para API
|
||||
|
||||
```python
|
||||
from flask_sslify import SSLify
|
||||
|
||||
sslify = SSLify(app) # Fuerza HTTPS
|
||||
```
|
||||
|
||||
#### Conexiones Encriptadas
|
||||
|
||||
- **Base de Datos:** Usar `encrypt=yes` en connection string
|
||||
- **FTP:** Considerar FTPS (FTP over SSL)
|
||||
- **SFTP:** Ya encriptado por defecto
|
||||
- **SharePoint:** HTTPS obligatorio
|
||||
|
||||
### En Reposo
|
||||
|
||||
#### Encriptar Archivos Excel
|
||||
|
||||
```python
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Protection
|
||||
|
||||
wb = Workbook()
|
||||
ws = Protection.set_password('password_seguro')
|
||||
wb.security = Protection(workbookPassword='password_seguro')
|
||||
```
|
||||
|
||||
#### Encriptar Base de Datos
|
||||
|
||||
Configurar SQL Server con Transparent Data Encryption (TDE).
|
||||
|
||||
## Control de Acceso
|
||||
|
||||
### Principio de Menor Privilegio
|
||||
|
||||
#### Usuario de Base de Datos
|
||||
|
||||
```sql
|
||||
-- Crear usuario con permisos mínimos
|
||||
CREATE USER datatransfer_user WITH PASSWORD = 'password';
|
||||
GRANT SELECT ON Cobertura TO datatransfer_user;
|
||||
GRANT SELECT ON Checkout TO datatransfer_user;
|
||||
-- Solo permisos de lectura
|
||||
```
|
||||
|
||||
#### Usuario FTP
|
||||
|
||||
- Solo permisos de escritura en directorio específico
|
||||
- No permisos de lectura/eliminación
|
||||
|
||||
#### Usuario SharePoint
|
||||
|
||||
- Acceso solo a document libraries específicas
|
||||
- Permisos de Contributor (no Owner)
|
||||
|
||||
### Network Security
|
||||
|
||||
#### Firewall Rules
|
||||
|
||||
```bash
|
||||
# Solo permitir conexiones desde IPs específicas
|
||||
ufw allow from 192.168.1.0/24 to any port 5000
|
||||
ufw allow from 10.0.0.0/8 to any port 5000
|
||||
ufw deny from 0.0.0.0/0 to any port 5000
|
||||
```
|
||||
|
||||
#### VPC/Subnets
|
||||
|
||||
- Desplegar en red privada
|
||||
- Usar NAT Gateway para acceso outbound
|
||||
- Security Groups restrictivos
|
||||
|
||||
## Auditoría y Monitoreo
|
||||
|
||||
### Logging Seguro
|
||||
|
||||
```python
|
||||
# No loggear credenciales
|
||||
logger.info(f"Connected to database: {db_config['server']}")
|
||||
# ❌ MAL: logger.info(f"Connected with user: {USERNAME}")
|
||||
|
||||
# Sanitizar datos sensibles en logs
|
||||
def sanitize_log(message):
|
||||
# Remover passwords, tokens, etc.
|
||||
return re.sub(r'password=\w+', 'password=***', message)
|
||||
```
|
||||
|
||||
### Monitoreo de Seguridad
|
||||
|
||||
#### Detección de Intrusiones
|
||||
|
||||
- Monitorear logs para patrones sospechosos
|
||||
- Alertas en accesos desde IPs desconocidas
|
||||
- Rate limiting para prevenir ataques de fuerza bruta
|
||||
|
||||
#### Vulnerability Scanning
|
||||
|
||||
```bash
|
||||
# Escanear dependencias
|
||||
safety check
|
||||
pip-audit
|
||||
|
||||
# Escanear imagen Docker
|
||||
docker scan datatransfer:latest
|
||||
```
|
||||
|
||||
## Backup y Recuperación
|
||||
|
||||
### Estrategia de Backup
|
||||
|
||||
#### Configuración
|
||||
|
||||
```bash
|
||||
# Backup de configs
|
||||
tar -czf config_backup_$(date +%Y%m%d).tar.gz App/Config/
|
||||
|
||||
# Versionado en Git (sin secrets)
|
||||
git add App/Config/
|
||||
git commit -m "Config update"
|
||||
```
|
||||
|
||||
#### Datos
|
||||
|
||||
- **Reportes:** Backup automático en storage redundante
|
||||
- **Logs:** Rotación y compresión semanal
|
||||
- **Base de Datos:** Backup SQL Server programado
|
||||
|
||||
### Plan de Recuperación
|
||||
|
||||
#### Disaster Recovery
|
||||
|
||||
1. **Restaurar desde backup**
|
||||
2. **Reconfigurar credenciales**
|
||||
3. **Verificar integridad**
|
||||
4. **Reanudar operaciones**
|
||||
|
||||
#### Business Continuity
|
||||
|
||||
- **RTO (Recovery Time Objective):** 4 horas
|
||||
- **RPO (Recovery Point Objective):** 1 hora
|
||||
- **Multi-region:** Despliegue en múltiples zonas
|
||||
|
||||
## Cumplimiento
|
||||
|
||||
### GDPR (Europa)
|
||||
|
||||
- **Derecho al olvido:** Capacidad de eliminar datos
|
||||
- **Consentimiento:** Documentar uso de datos
|
||||
- **Auditoría:** Logs de acceso a datos personales
|
||||
|
||||
### SOX (EEUU)
|
||||
|
||||
- **Controles internos:** Validación de procesos ETL
|
||||
- **Auditoría financiera:** Traceability de datos
|
||||
- **Integridad:** Checks de validación de datos
|
||||
|
||||
### ISO 27001
|
||||
|
||||
- **Asset Management:** Inventario de datos sensibles
|
||||
- **Access Control:** Autenticación multifactor
|
||||
- **Incident Management:** Procedimientos de respuesta
|
||||
|
||||
## Mejores Prácticas
|
||||
|
||||
### Desarrollo Seguro
|
||||
|
||||
1. **Code Reviews:** Revisar código por seguridad
|
||||
2. **Dependency Scanning:** Verificar vulnerabilidades en paquetes
|
||||
3. **Input Validation:** Sanitizar todas las entradas
|
||||
4. **Error Handling:** No exponer información sensible en errores
|
||||
|
||||
### Despliegue Seguro
|
||||
|
||||
1. **Imágenes Base:** Usar imágenes oficiales y actualizadas
|
||||
2. **Secrets:** Nunca en código o imágenes
|
||||
3. **Network:** Principio de zero trust
|
||||
4. **Monitoring:** Alertas en tiempo real
|
||||
|
||||
### Operaciones Seguras
|
||||
|
||||
1. **Access Management:** Rotación regular de credenciales
|
||||
2. **Backup Testing:** Verificar restauración periódicamente
|
||||
3. **Incident Response:** Plan documentado y probado
|
||||
4. **Training:** Capacitación en seguridad para equipo
|
||||
|
||||
## Checklist de Seguridad
|
||||
|
||||
### Antes de Producción
|
||||
|
||||
- [ ] Credenciales en variables de entorno
|
||||
- [ ] HTTPS configurado
|
||||
- [ ] Autenticación implementada
|
||||
- [ ] Rate limiting activo
|
||||
- [ ] Logs sanitizados
|
||||
- [ ] Backup funcionando
|
||||
- [ ] Firewall configurado
|
||||
- [ ] Dependencias actualizadas
|
||||
|
||||
### Monitoreo Continuo
|
||||
|
||||
- [ ] Alertas de seguridad activas
|
||||
- [ ] Logs revisados regularmente
|
||||
- [ ] Vulnerabilidades escaneadas
|
||||
- [ ] Accesos auditados
|
||||
- [ ] Backups verificados
|
||||
@@ -0,0 +1,188 @@
|
||||
# Uso
|
||||
|
||||
## Modos de Ejecución
|
||||
|
||||
DataTransferV2 puede ejecutarse de tres formas principales: automática, interfaz web y API.
|
||||
|
||||
## Ejecución Automática
|
||||
|
||||
### Comando Principal
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
Este comando procesa todos los proyectos activos (PG, FEDURO) con todos sus reportes en una ventana de 3 días (hoy, ayer, anteayer).
|
||||
|
||||
### Salida Esperada
|
||||
|
||||
- Registros de progreso en consola
|
||||
- Archivos Excel generados en `Reportes/<PROYECTO>/<REPORTE>/`
|
||||
- Notificación WhatsApp con resumen de ejecución
|
||||
- Logs detallados en `Logs/etl.log`
|
||||
|
||||
### Ejemplo de Salida
|
||||
|
||||
```
|
||||
Iniciando ETL para proyecto: PG
|
||||
Procesando reporte: Cobertura - Fecha: 2024-01-15
|
||||
✅ SUCCESS: Reporte generado y distribuido
|
||||
...
|
||||
Resumen PG: Total: 16, Éxito: 15, Errores: 1, Advertencias: 0
|
||||
```
|
||||
|
||||
## Interfaz Web
|
||||
|
||||
### Iniciar la UI
|
||||
|
||||
```bash
|
||||
cd App
|
||||
python -m flask run
|
||||
```
|
||||
|
||||
Accede a `http://localhost:5000` en tu navegador.
|
||||
|
||||
### Funcionalidades
|
||||
|
||||
- **Selección de Proyecto:** PG, FEDURO, Corripio
|
||||
- **Selección de Reporte:** Lista desplegable con reportes disponibles
|
||||
- **Rango de Fechas:** Selector de fecha inicio/fin
|
||||
- **Ejecución Manual:** Botón para procesar la selección
|
||||
|
||||
### Uso
|
||||
|
||||
1. Selecciona proyecto y reporte
|
||||
2. Elige fechas de inicio y fin
|
||||
3. Haz clic en "Ejecutar ETL"
|
||||
4. Monitorea el progreso y resultados
|
||||
|
||||
## API REST
|
||||
|
||||
### Endpoint Principal
|
||||
|
||||
```
|
||||
GET /api/download
|
||||
```
|
||||
|
||||
### Parámetros
|
||||
|
||||
- `project` (requerido): Nombre del proyecto (pg, feduro)
|
||||
- `task` (requerido): Nombre del reporte
|
||||
- `start_date` (requerido): Fecha inicio (YYYY-MM-DD)
|
||||
- `end_date` (requerido): Fecha fin (YYYY-MM-DD)
|
||||
|
||||
### Ejemplo de Uso
|
||||
|
||||
```bash
|
||||
curl "http://localhost:5000/api/download?project=pg&task=Cobertura&start_date=2024-01-01&end_date=2024-01-31"
|
||||
```
|
||||
|
||||
### Respuesta
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": [
|
||||
{
|
||||
"fecha": "2024-01-01",
|
||||
"campo1": "valor1",
|
||||
"campo2": "valor2"
|
||||
}
|
||||
],
|
||||
"count": 100
|
||||
}
|
||||
```
|
||||
|
||||
### Códigos de Estado
|
||||
|
||||
- `200`: Éxito
|
||||
- `400`: Parámetros inválidos
|
||||
- `404`: Proyecto/reporte no encontrado
|
||||
- `500`: Error interno
|
||||
|
||||
## Programación Automática
|
||||
|
||||
### Usando APScheduler
|
||||
|
||||
El código incluye APScheduler para ejecución programada. Para activarlo:
|
||||
|
||||
```python
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
|
||||
scheduler = BackgroundScheduler()
|
||||
scheduler.add_job(run_etl_pipeline, 'interval', hours=2)
|
||||
scheduler.start()
|
||||
```
|
||||
|
||||
### Usando Cron (Linux/macOS)
|
||||
|
||||
```bash
|
||||
# Ejecutar cada 2 horas
|
||||
0 */2 * * * /path/to/env/bin/python /path/to/main.py
|
||||
```
|
||||
|
||||
### Usando Task Scheduler (Windows)
|
||||
|
||||
1. Crear tarea básica
|
||||
2. Programa: `python.exe`
|
||||
3. Argumentos: `main.py`
|
||||
4. Ejecutar cada 2 horas
|
||||
|
||||
## Monitoreo y Logs
|
||||
|
||||
### Archivos de Log
|
||||
|
||||
- `Logs/etl.log`: Logs del proceso ETL
|
||||
- `Logs/api.log`: Logs de la API
|
||||
- `Logs/reports.log`: Logs de generación de reportes
|
||||
|
||||
### Base de Datos de Auditoría
|
||||
|
||||
Todas las ejecuciones se registran en la tabla `ExecutionLog` de SQL Server con:
|
||||
- ID de procedimiento
|
||||
- Estado (SUCCESS, FAILED, WARNING)
|
||||
- Mensajes de error
|
||||
- Timestamps
|
||||
|
||||
## Reportes Generados
|
||||
|
||||
### Ubicación
|
||||
|
||||
```
|
||||
Reportes/
|
||||
├── FEDURO/
|
||||
│ ├── Cobertura/
|
||||
│ │ ├── Cobertura-20240115.xlsx
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
└── PG/
|
||||
├── Checkout/
|
||||
│ ├── Checkout-20240115.xlsx
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||
|
||||
### Formato
|
||||
|
||||
- **Tipo:** Excel (.xlsx)
|
||||
- **Librería:** Pandas + OpenPyXL
|
||||
- **Contenido:** Datos tabulares de consultas SQL
|
||||
|
||||
## Notificaciones
|
||||
|
||||
### WhatsApp
|
||||
|
||||
Después de cada proyecto, se envía un resumen via webhook:
|
||||
|
||||
```
|
||||
✅ PG - Completado
|
||||
Total: 16, Éxito: 15, Errores: 1
|
||||
Tiempo: 45 minutos
|
||||
```
|
||||
|
||||
### Estados
|
||||
|
||||
- ✅ SUCCESS: Todo correcto
|
||||
- ⚠️ COMPLETED_WITH_ERRORS: Errores no críticos
|
||||
- ❌ FAILED: Fallo crítico
|
||||
- ℹ️ WARNING: Sin datos (ignorados si domingo)
|
||||
Reference in New Issue
Block a user