"""Cuerpos HTML de los correos de notificación."""
from pipeline_utils import importes_coinciden
# ============================================================================
def build_validation_html(resultados: list[dict]) -> str:
"""
Genera una tabla HTML con el resultado de la validación de precios
para incluir en el cuerpo del email de notificación.
Args:
resultados: Lista de resultados de ``validate_prices``.
Returns:
str — Código HTML de la tabla con columnas:
Guía, Estado, Draft Price, SAP, Almacén, Resultado.
Example:
Con un resultado ``ok=True`` y ``grflete="09T001-127773"``::
html = build_validation_html(resultados)
# → "
"
"""
rows = ""
for r in resultados:
icono = "✅" if r["ok"] else "❌"
dp = f"{r['draft_price']:.6f}" if r["draft_price"] is not None else "-"
sap_price_str = f"{r['sap_price']:.6f}" if r["sap_price"] is not None else "-"
rows += f"| {r['grflete']} | {icono} | {dp} | {sap_price_str} | {r['warehouse_code']} | {r['label']} |
"
return (
""
"| Guía | Estado | Draft Price | SAP | Almacén | Resultado |
"
f"{rows}
"
)
# ============================================================================
def build_valor_referencial_html(factura: dict, guias_valor_ref: list[dict]) -> str:
"""
Genera una tabla HTML comparando el valor referencial del XML de la
factura contra el valor referencial obtenido en SAP
(``Sp_ObtenerValorReferencial``) por cada guía de remisión, y el
total acumulado.
Args:
factura: Diccionario de la factura (usa ``lineas[]`` para sumar
``valor_referencial`` extraído del XML).
guias_valor_ref: Resultado de ``obtener_valor_referencial_sap``.
Returns:
str — Tabla HTML con una fila por guía, el total SAP, el valor
del XML y un ícono de coincidencia.
"""
valor_xml = sum(l.get("valor_referencial") or 0 for l in factura.get("lineas", []))
total_sap = sum(g["valor_sap"] for g in guias_valor_ref)
rows = "".join(
f"| 09{g['serie']}-{g['numero']} | {g['valor_sap']:.2f} |
"
for g in guias_valor_ref
)
coincide = importes_coinciden(valor_xml, total_sap)
icono = "✅" if coincide else "❌"
return (
""
"| Guía de Remisión | Valor Referencial SAP |
"
f"{rows}"
f"| Total SAP | {total_sap:.2f} |
"
f"| Valor Referencial XML | {valor_xml:.2f} |
"
f"| {icono} {'Coincide' if coincide else 'No coincide'} |
"
"
"
)
# ============================================================================
def build_notification_body(status: str, factura: dict, validation_table: str, valor_referencial_table: str, **kwargs) -> str:
"""
Construye el cuerpo HTML del email de notificación del resultado
del proceso SAP.
Args:
status: ``"created"`` (draft creado), ``"duplicate"`` (la factura ya
existe en SAP), ``"error"`` (error al
crear), o cualquier otro valor (validación falló, draft no
creado).
factura: Diccionario de la factura (se usa ``serie``,
``numero``, ``razon_social_emisor``).
validation_table: Tabla HTML generada por
``build_validation_html``.
valor_referencial_table: Tabla HTML generada por
``build_valor_referencial_html``.
**kwargs: Argumentos adicionales:
- ``doc_entry`` (int): DocEntry del draft creado.
- ``error`` (str): Mensaje de error si ocurrió.
Returns:
str — Cuerpo HTML completo del email.
Example:
Draft creado exitosamente::
body = build_notification_body(
"created", factura, tabla_html, valref_html, doc_entry=2021
)
# → "✅ Draft SAP B1 creado exitosamente.
..."
"""
base = (
f"Factura: {factura.get('serie')}-{factura.get('numero')}
"
f"Emisor: {factura.get('razon_social_emisor', '')}
"
)
valref_section = f"Valor Referencial (XML vs SAP)
{valor_referencial_table}"
if status == "created":
return f"✅ Draft SAP B1 creado exitosamente.
DocEntry: {kwargs.get('doc_entry')}
{base}Validación de precios
{validation_table}{valref_section}"
elif status == "duplicate":
existente = kwargs.get("existente") or {}
return f"⏭️ Draft NO creado: la factura ya existe en SAP ({existente.get('entidad')} {existente.get('DocEntry')}).
{base}"
elif status == "error":
return f"❌ Error al crear Draft SAP B1.
{base}Error: {kwargs.get('error')}
Validación de precios
{validation_table}{valref_section}"
else:
return f"⏭️ Draft NO creado. Los precios de las guías no coinciden con SAP.
{base}Validación de precios
{validation_table}{valref_section}"