Files
descarga_factura_transporte/docs/main.md
T
GeorgeandClaude Sonnet 5.5 f01f21b1c3 se completan los horarios, se fijan las rutas al código y se muestra la versión
- HORARIOS cubre las 24 horas: se agregan 21:30-24:00 (cada 60 min) y
  05:00-06:30 (cada 30 min); antes el demonio dormía hasta las 06:30 en esos
  tramos. Se corrigen los comentarios, que no coincidían con los valores.
  tests/test_horarios.py garantiza que no haya huecos ni solapes.
- La carpeta de resultados se resuelve junto al código, no relativa al cwd
  (un servicio de Windows puede arrancar desde cualquier carpeta).
- copiar_a_red no crea carpetas locales cuando RUTA_RED_FACTURACION no es una
  ruta absoluta en el sistema operativo (una UNC fuera de Windows); antes el
  draft podía referenciar archivos que no estaban en el recurso compartido.
- El log muestra la versión del proyecto (pyproject.toml) al arrancar.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 12:08:38 -05:00

110 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# main.py — Mapa del flujo
## Estructura general
```
main.py
├── Constantes: HORARIOS (7 bloques que cubren las 24 horas)
├── obtener_intervalo(dt) → (intervalo, modo) | None
├── segundos_hasta_proximo_inicio(dt) → int
├── non_negative_int(value) → int (validador argparse)
└── main() → None (bucle infinito envuelto en try/except KeyboardInterrupt)
```
## Proceso de `main()`
```mermaid
flowchart TD
A[Inicio main] --> B[Parsear args --dias]
B --> C[Cargar .env → EMAIL, DOWNLOAD_FOLDER, OUTPUT_FOLDER]
C --> Z[try:]
Z --> D{Bucle infinito}
D --> E[inicio_ciclo = datetime.now]
E --> F[obtener_intervalo inicio_ciclo]
F -- Sí, está en horario --> G[Extraer intervalo, modo]
G --> H[run_pipeline]:::highlight
H --> I[Calcular duración real]
I --> J{Duración > intervalo?}
J -- Sí --> K[⚠️ Warning]
J -- No --> L[dormir = intervalo - duración]
K --> L
L --> M[💤 Próximo ciclo en dormir seg]
M --> N[time.sleep dormir]
N --> E
F -- No, fuera de horario --> O[dormir = segundos_hasta_proximo_inicio]
O --> P[Log próxima ejecución]
P --> N
D -. KeyboardInterrupt .-> Q[🛑 Demonio detenido por el usuario]
classDef highlight fill:#fff3e0,stroke:#e65100,stroke-width:3px;
```
### Paso a paso
```
main()
│
├── 1. Parsear args (--dias, default=2)
│
├── 2. Cargar .env → EMAIL, DOWNLOAD_FOLDER, OUTPUT_FOLDER
│
├── 3. try:
│ └── LOOP INFINITO (while True):
│ │
│ ├── 3.1. inicio_ciclo = datetime.now()
│ │
│ ├── 3.2. resultado = obtener_intervalo(inicio_ciclo)
│ │ │
│ ├── ¿Sí está en horario?
│ │ │
│ │ ├── Extraer (intervalo, modo)
│ │ ├── run_pipeline(dias, EMAIL, DOWNLOAD_FOLDER, OUTPUT_FOLDER)
│ │ ├── Calcular duración real del ciclo
│ │ ├── ⚠️ Si duración > intervalo → warning
│ │ └── dormir = max(0, intervalo - duración)
│ │
│ └── ¿No está en horario?
│ │
│ ├── dormir = segundos_hasta_proximo_inicio() (06:30 del día siguiente; rama inalcanzable mientras los bloques cubran el día)
│ └── Log "Fuera del horario, próxima ejecución en..."
│ │
│ └── 3.3. time.sleep(dormir) → vuelve a 3.1
│
└── except KeyboardInterrupt: 🛑 "Demonio detenido por el usuario" (sin traceback)
```
## Bloques horarios definidos
| Desde | Hasta | Intervalo | Modo |
|---------|---------|-----------|----------|
| 00:00 | 05:00 | 60s | rápido |
| 05:00 | 06:30 | 1800s | full |
| 06:30 | 13:15 | 300s | rápido |
| 13:15 | 14:00 | 1800s | full |
| 14:00 | 18:30 | 300s | rápido |
| 18:30 | 21:30 | 3600s | full |
| 21:30 | 24:00 | 3600s | full |
Los bloques cubren las 24 horas sin huecos ni solapes (lo comprueba `tests/test_horarios.py`). El modo (`rápido`/`full`) solo se registra en el log: `run_pipeline` se ejecuta igual en ambos. Antes de la versión 1.2.0 los tramos 21:30–00:00 y 05:00–06:30 no tenían bloque y el demonio dormía hasta las 06:30.
## Entry point (línea 126-134)
```
if __name__ == "__main__":
1. logger_manager.setup_logging()
└── Configura logging a archivo rotado (logs/descarga_factura_transporte.log,
rotación diaria, 30 días de historial) + consola, y redirige print()/stderr
al mismo log (los módulos del pipeline ya usan logger con nivel explícito;
los print() restantes se registran como INFO).
2. logger.info(...) banner de inicio, incluyendo logger_manager.LOG_FILE
3. main()
└── Tras load_dotenv(), config_validator.verificar_configuracion():
termina con código 1 si falta alguna variable obligatoria del .env
(ver config_validator.OBLIGATORIAS) y advierte si la verificación SSL
está desactivada o no hay ruta de red.
```