2026-10-14 22:46:41 -05:00
|
|
|
"""
|
|
|
|
|
Validación de la configuración (.env) al arrancar el proceso.
|
|
|
|
|
|
|
|
|
|
Falla rápido con un mensaje claro si falta alguna variable obligatoria, en
|
|
|
|
|
lugar de descubrirlo a mitad de un ciclo (por ejemplo, adjuntos descargados
|
|
|
|
|
en la raíz del proyecto por un ``DOWNLOAD_FOLDER`` vacío, o consultas a HANA
|
|
|
|
|
que devuelven 0 en silencio por credenciales ausentes).
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
# Variables obligatorias, agrupadas por servicio para el mensaje de error.
|
|
|
|
|
OBLIGATORIAS = {
|
|
|
|
|
"Pipeline": ["EMAIL", "DOWNLOAD_FOLDER", "OUTPUT_FOLDER"],
|
|
|
|
|
"Microsoft Graph": ["CLIENT_ID", "CLIENT_SECRET", "TENANT_ID"],
|
|
|
|
|
"SAP B1 Service Layer": ["SAP_B1_URL", "SAP_B1_COMPANY", "SAP_B1_USER", "SAP_B1_PASSWORD"],
|
|
|
|
|
"SAP HANA": ["HANA_SERVER", "HANA_USER", "HANA_PASSWORD", "HANA_SCHEMA"],
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-22 08:55:54 -05:00
|
|
|
# Modos de ``NOTIFICACION_MODO``: ver respuesta_proveedor.py
|
|
|
|
|
MODOS_NOTIFICACION = ("prueba", "real")
|
|
|
|
|
|
2026-10-14 22:46:41 -05:00
|
|
|
# Variable de verificación SSL → servicio al que aplica. Cada módulo solo
|
|
|
|
|
# la activa con el valor "true" (cualquier otro valor, o ausente, la desactiva).
|
|
|
|
|
VERIFICACION_SSL = {
|
|
|
|
|
"VERIFY_SSL": "Microsoft Graph",
|
|
|
|
|
"SAP_B1_VERIFY_SSL": "SAP B1 Service Layer",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def validar_configuracion() -> tuple[list[str], list[str]]:
|
|
|
|
|
"""
|
|
|
|
|
Revisa las variables de entorno ya cargadas (tras ``load_dotenv``).
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
tuple[list[str], list[str]]: ``(errores, advertencias)``. Los errores
|
|
|
|
|
impiden arrancar; las advertencias solo se registran.
|
|
|
|
|
"""
|
|
|
|
|
errores: list[str] = []
|
|
|
|
|
advertencias: list[str] = []
|
|
|
|
|
|
|
|
|
|
for servicio, variables in OBLIGATORIAS.items():
|
|
|
|
|
faltan = [v for v in variables if not os.getenv(v, "").strip()]
|
|
|
|
|
if faltan:
|
|
|
|
|
errores.append(f"{servicio}: faltan {', '.join(faltan)}")
|
|
|
|
|
|
|
|
|
|
ruta_red = os.getenv("RUTA_RED_FACTURACION", "").strip()
|
|
|
|
|
ruc_empresa = os.getenv("RUC_EMPRESA", "").strip()
|
|
|
|
|
if ruta_red and not ruc_empresa:
|
|
|
|
|
errores.append("Ruta de red: RUTA_RED_FACTURACION está definida pero falta RUC_EMPRESA")
|
|
|
|
|
elif not ruta_red:
|
|
|
|
|
advertencias.append(
|
|
|
|
|
"RUTA_RED_FACTURACION no definida: no se copiarán PDF/XML a la red "
|
|
|
|
|
"y U_VS_ANEXO_PDF/XML irán vacíos en el draft"
|
|
|
|
|
)
|
|
|
|
|
|
2026-10-22 08:55:54 -05:00
|
|
|
modo = os.getenv("NOTIFICACION_MODO", "").strip().lower()
|
|
|
|
|
if modo and modo not in MODOS_NOTIFICACION:
|
|
|
|
|
advertencias.append(f"NOTIFICACION_MODO='{modo}' no es válido (usa {' o '.join(MODOS_NOTIFICACION)}); se usará prueba")
|
|
|
|
|
elif modo == "real":
|
|
|
|
|
advertencias.append("Modo de notificación REAL: las respuestas se envían a quien envía el correo")
|
|
|
|
|
else:
|
|
|
|
|
advertencias.append("Modo de notificación PRUEBA: las respuestas van al equipo, no a quien envía el correo")
|
|
|
|
|
if not os.getenv("NOTIFICACION_EQUIPO", "").strip():
|
|
|
|
|
advertencias.append("NOTIFICACION_EQUIPO no definida: se usa la lista por defecto del equipo")
|
|
|
|
|
if not os.getenv("LOGO_URL", "").strip():
|
|
|
|
|
advertencias.append("LOGO_URL no definida: los correos al proveedor saldrán sin logo")
|
|
|
|
|
|
2026-10-14 22:46:41 -05:00
|
|
|
nivel = os.getenv("LOG_LEVEL", "").strip()
|
|
|
|
|
if nivel and not isinstance(getattr(logging, nivel.upper(), None), int):
|
|
|
|
|
advertencias.append(f"LOG_LEVEL='{nivel}' no es un nivel válido; se usará INFO")
|
|
|
|
|
|
|
|
|
|
for variable, servicio in VERIFICACION_SSL.items():
|
|
|
|
|
if os.getenv(variable, "").strip().lower() != "true":
|
|
|
|
|
advertencias.append(f"Verificación SSL desactivada para {servicio} ({variable} distinto de 'true')")
|
|
|
|
|
|
|
|
|
|
return errores, advertencias
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def verificar_configuracion() -> None:
|
|
|
|
|
"""
|
|
|
|
|
Registra las advertencias y, si hay errores, los registra y termina el
|
|
|
|
|
proceso con código 1.
|
|
|
|
|
"""
|
|
|
|
|
errores, advertencias = validar_configuracion()
|
|
|
|
|
|
|
|
|
|
for a in advertencias:
|
|
|
|
|
logger.warning(f"⚠️ Configuración: {a}")
|
|
|
|
|
|
|
|
|
|
if errores:
|
|
|
|
|
logger.error("❌ Configuración incompleta en .env:")
|
|
|
|
|
for e in errores:
|
|
|
|
|
logger.error(f" - {e}")
|
|
|
|
|
sys.exit(1)
|