116 lines
4.9 KiB
Python
116 lines
4.9 KiB
Python
"""
|
|||
|
|
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,"
|
||
|
|
"<svg xmlns='http://www.w3.org/2000/svg' width='117' height='28'>"
|
||
|
|
"<rect width='117' height='28' fill='%23FF6900'/>"
|
||
|
|
"<text x='58' y='19' font-family='Arial' font-size='14' font-weight='bold' fill='%23282828' text-anchor='middle'>Aberio</text>"
|
||
|
|
"</svg>"
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
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 <nombre> (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()
|