""" Renderiza las plantillas de correo (plantilla/plantilla-*.html) con los datos de ejemplo de plantilla/ejemplos.json, para revisarlas en el navegador o enviarse un correo de prueba. Uso (desde cualquier directorio): python tools/previsualizar_plantillas.py --listar python tools/previsualizar_plantillas.py --abrir # todos los escenarios python tools/previsualizar_plantillas.py --escenario aceptado_con_pago --abrir python tools/previsualizar_plantillas.py --escenario rechazado_dos_observaciones --enviar yo@dominio.com otro@dominio.com Los HTML se guardan en tools/previews/ (ignorada por git). Para probar otros textos, edita plantilla/ejemplos.json: el renderizado es estricto y avisa si falta algún dato. ``--enviar`` manda el correo real con Microsoft Graph desde el buzón EMAIL del .env, con el asunto prefijado con "[PRUEBA]". Exige indicar el escenario (o ``todos``). En el correo enviado el logo queda vacío mientras ``logo_url`` no tenga una URL pública. """ import argparse import json import os import sys import webbrowser RAIZ = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") sys.path.insert(0, RAIZ) from dotenv import load_dotenv import plantillas RUTA_EJEMPLOS = os.path.join(plantillas.CARPETA_PLANTILLAS, "ejemplos.json") SALIDA_POR_DEFECTO = os.path.join(os.path.dirname(os.path.abspath(__file__)), "previews") # Solo para la vista previa local: los clientes de correo no muestran imágenes data: LOGO_PROVISIONAL = ( "data:image/svg+xml;utf8," "" "" "Aberio" "" ) def cargar_ejemplos() -> dict: with open(RUTA_EJEMPLOS, encoding="utf-8") as f: return json.load(f) def seleccionar(ejemplos: dict, escenario: str | None) -> dict: if escenario in (None, "todos"): return ejemplos if escenario not in ejemplos: sys.exit(f"❌ Escenario '{escenario}' no existe. Disponibles: {', '.join(ejemplos)}") return {escenario: ejemplos[escenario]} def renderizar(ejemplo: dict, para_navegador: bool) -> str: contexto = dict(ejemplo["contexto"]) if para_navegador and not contexto.get("logo_url"): contexto["logo_url"] = LOGO_PROVISIONAL return plantillas.renderizar_plantilla(ejemplo["plantilla"], contexto) def main() -> None: parser = argparse.ArgumentParser(description="Vista previa y envío de prueba de las plantillas de correo.") parser.add_argument("--listar", action="store_true", help="Lista los escenarios disponibles y termina.") parser.add_argument("--escenario", "-e", help="Nombre del escenario, o 'todos'. Por defecto, todos (obligatorio con --enviar).") parser.add_argument("--salida", default=SALIDA_POR_DEFECTO, help="Carpeta donde se guardan los HTML.") parser.add_argument("--abrir", action="store_true", help="Abre cada HTML en el navegador.") parser.add_argument("--enviar", metavar="CORREO", nargs="+", help="Envía el escenario a estos correos como prueba (uno o varios).") args = parser.parse_args() ejemplos = cargar_ejemplos() if args.listar: for nombre, e in ejemplos.items(): print(f"{nombre:32} ({e['plantilla']}) {e['contexto']['asunto']}") return if args.enviar and not args.escenario: sys.exit("❌ Con --enviar indica el escenario: --escenario (o --escenario todos).") elegidos = seleccionar(ejemplos, args.escenario) os.makedirs(args.salida, exist_ok=True) for nombre, ejemplo in elegidos.items(): ruta = os.path.join(args.salida, f"{nombre}.html") with open(ruta, "w", encoding="utf-8") as f: f.write(renderizar(ejemplo, para_navegador=True)) print(f"📄 {os.path.relpath(ruta)}") if args.abrir: webbrowser.open("file://" + os.path.abspath(ruta)) if args.enviar: import outlook_utilities load_dotenv(dotenv_path=os.path.join(RAIZ, ".env")) buzon = os.getenv("EMAIL", "") if not buzon: sys.exit("❌ EMAIL no configurado en .env") try: token = outlook_utilities.get_access_token() except Exception as ex: sys.exit(f"❌ No se pudo obtener el token de Microsoft Graph, no se envió nada:\n {ex}") if not token: sys.exit("❌ No se pudo obtener el token de Microsoft Graph, no se envió nada") for nombre, ejemplo in elegidos.items(): asunto = f"[PRUEBA] {ejemplo['contexto']['asunto']}" ok = outlook_utilities.send_email(token, buzon, args.enviar, asunto, renderizar(ejemplo, para_navegador=False)) print(f"{'✉️ Enviado' if ok else '❌ Falló'}: {asunto} → {', '.join(args.enviar)}") if __name__ == "__main__": main()