diff --git a/main.py b/main.py index a37922b..b7fd931 100644 --- a/main.py +++ b/main.py @@ -1,11 +1,42 @@ import os +import time import argparse -from datetime import datetime +from datetime import datetime, timedelta from dotenv import load_dotenv import logger_utilities from pipeline import run_pipeline +# ============================================================================ + +HORARIOS = [ + (6, 30, 13, 15, 300, "rapido"), # 06:30 - 13:15 -> cada 5 minutos + (13, 15, 14, 0, 1800, "full"), # 13:15 - 14:00 -> cada 30 minutos + (14, 0, 18, 30, 300, "rapido"), # 14:00 - 17:30 -> cada 5 minutos + (18, 30, 21, 30, 3600, "full"), # 17:30 - 21:30 -> cada 60 minutos +] +# ============================================================================ +def obtener_intervalo(dt: datetime) -> tuple[int, str] | None: + minutos = dt.hour * 60 + dt.minute + + for hi, mi, hf, mf, intervalo, modo in HORARIOS: + inicio = hi * 60 + mi + fin = hf * 60 + mf + + if inicio <= minutos < fin: + return (intervalo, modo) + + return None + +# ============================================================================ +def segundos_hasta_proximo_inicio(dt: datetime) -> int: + inicio = dt.replace(hour=6, minute=30, second=0, microsecond=0) + + if dt >= inicio: + inicio += timedelta(days=1) + + return int((inicio - dt).total_seconds()) + # ============================================================================ def non_negative_int(value: str) -> int: ivalue = int(value) @@ -33,18 +64,57 @@ def main() -> None: dias = args.dias - if dias == 0: - print("馃搵 Obteniendo correos electr贸nicos de Office365 hoy.") - else: - print(f"馃搵 Obteniendo correos electr贸nicos de Office365 desde hace {dias} d铆as hasta hoy.") - load_dotenv(dotenv_path=".env.dev") EMAIL = os.getenv("EMAIL", "") DOWNLOAD_FOLDER = os.getenv("DOWNLOAD_FOLDER", "") OUTPUT_FOLDER = os.getenv("OUTPUT_FOLDER", "") - run_pipeline(dias, EMAIL, DOWNLOAD_FOLDER, OUTPUT_FOLDER) + print("馃殌 Demonio iniciado") + print("=" * 60) + + while True: + + inicio_ciclo = datetime.now() + + resultado = obtener_intervalo(inicio_ciclo) + + if resultado is not None: + + intervalo, modo = resultado + + print( + f"\n[{inicio_ciclo:%Y-%m-%d %H:%M:%S}] " + f"Iniciando ciclo [{modo}] (cada {intervalo}s)" + ) + + run_pipeline(dias, EMAIL, DOWNLOAD_FOLDER, OUTPUT_FOLDER) + + duracion = (datetime.now() - inicio_ciclo).total_seconds() + + if duracion > intervalo: + print( + f"鈿狅笍 El ciclo demor贸 {duracion:.1f}s " + f"(intervalo configurado {intervalo}s)" + ) + + dormir = max(0, intervalo - duracion) + + print(f"馃挙 Pr贸ximo ciclo [{modo}] en {dormir:.0f}s...") + + else: + + dormir = segundos_hasta_proximo_inicio(inicio_ciclo) + + despertar = inicio_ciclo + timedelta(seconds=dormir) + + print( + f"\n[{inicio_ciclo:%Y-%m-%d %H:%M:%S}] " + f"Fuera del horario.\n" + f"Pr贸xima ejecuci贸n: {despertar:%Y-%m-%d %H:%M:%S}" + ) + + time.sleep(dormir) # ============================================================================ @@ -52,17 +122,9 @@ if __name__ == "__main__": log_path = logger_utilities.setup_logger() logger_utilities.limpiar_logs_antiguos(dias=30) - inicio = datetime.now() print("=" * 60) - print(f"馃殌 INICIO DE EJECUCI脫N: {inicio.strftime('%Y-%m-%d %H:%M:%S')}") + print(f"馃殌 Demonio iniciado: {datetime.now():%Y-%m-%d %H:%M:%S}") print(f"馃搫 Log guardado en: {log_path}") print("=" * 60) main() - - fin = datetime.now() - duracion = fin - inicio - print("\n" + "=" * 60) - print(f"馃弫 FIN DE EJECUCI脫N: {fin.strftime('%Y-%m-%d %H:%M:%S')}") - print(f"鈴憋笍 Duraci贸n total: {str(duracion).split('.')[0]}") - print("=" * 60) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..52f86c9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,27 @@ +[build-system] +requires = ["setuptools>=64"] +build-backend = "setuptools.backends._legacy:_Backend" + +[project] +name = "descarga_factura_transporte" +version = "1.1.0" +description = "Descarga y procesamiento de facturas de transporte desde Office365" +requires-python = ">=3.11" +dependencies = [ + "certifi==2026.6.17", + "cffi==2.1.0", + "charset-normalizer==3.4.9", + "cryptography==49.0.0", + "dotenv==0.9.9", + "idna==3.18", + "msal==1.37.0", + "pdfminer.six==20260107", + "pdfplumber==0.11.10", + "pillow==12.3.0", + "pycparser==3.0", + "PyJWT==2.13.0", + "pypdfium2==5.11.0", + "python-dotenv==1.2.2", + "requests==2.34.2", + "urllib3==2.7.0", +]