146 lines
5.0 KiB
Python
146 lines
5.0 KiB
Python
"""
|
|||
|
|
Flujo completo de ``pipeline._procesar_un_correo`` con SAP, HANA, Outlook y la
|
||
|
|
BD simulados. Usa el correo de prueba 001 (factura F002-2450, una línea de
|
||
|
|
624.38 con la guía T001-128912).
|
||
|
|
"""
|
||
|
|
import glob
|
||
|
|
import os
|
||
|
|
import shutil
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
import database_utilities
|
||
|
|
import hana_manager
|
||
|
|
import outlook_utilities
|
||
|
|
import pipeline
|
||
|
|
import sapb1_manager
|
||
|
|
from conftest import FIXTURES
|
||
|
|
|
||
|
|
CASO = "001_correo"
|
||
|
|
TOTAL_LINEA = 624.38
|
||
|
|
|
||
|
|
|
||
|
|
class Entorno:
|
||
|
|
"""Registra lo que el pipeline le pide a los servicios externos."""
|
||
|
|
|
||
|
|
def __init__(self):
|
||
|
|
self.line_total_sap = TOTAL_LINEA
|
||
|
|
self.error_al_crear = None
|
||
|
|
self.drafts = []
|
||
|
|
self.correos = []
|
||
|
|
self.descargas = 0
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def entorno(tmp_path, monkeypatch):
|
||
|
|
e = Entorno()
|
||
|
|
monkeypatch.setenv("RUTA_RED_FACTURACION", "")
|
||
|
|
|
||
|
|
monkeypatch.setattr(database_utilities, "get_existing_ids", lambda ids: [])
|
||
|
|
monkeypatch.setattr(database_utilities, "save_emails", lambda emails: None)
|
||
|
|
|
||
|
|
def descargar(addr, id_, token, carpeta):
|
||
|
|
e.descargas += 1
|
||
|
|
os.makedirs(carpeta, exist_ok=True) # como el download_attachments real
|
||
|
|
nombres = []
|
||
|
|
for ruta in glob.glob(os.path.join(FIXTURES, CASO, "*")):
|
||
|
|
if ruta.lower().endswith((".pdf", ".xml")):
|
||
|
|
shutil.copy(ruta, carpeta)
|
||
|
|
nombres.append(os.path.basename(ruta))
|
||
|
|
return nombres
|
||
|
|
|
||
|
|
def enviar(token, desde, para, asunto, html, adjuntos=None, cc_recipients=None):
|
||
|
|
e.correos.append({"para": para, "asunto": asunto, "html": html, "cc": cc_recipients, "adjuntos": adjuntos})
|
||
|
|
return True
|
||
|
|
|
||
|
|
def crear_draft(draft):
|
||
|
|
if e.error_al_crear:
|
||
|
|
raise e.error_al_crear
|
||
|
|
e.drafts.append(draft)
|
||
|
|
return {"DocEntry": 777}
|
||
|
|
|
||
|
|
def delivery_notes(**k):
|
||
|
|
return [{"Series": "1", "DocNum": "9", "U_IDC_DESTINO": "Z1", "DocumentLines": [
|
||
|
|
{"ItemCode": "FL10007", "LineTotal": e.line_total_sap, "PriceAfterVAT": 1.3396,
|
||
|
|
"Quantity": 466, "WarehouseCode": "A-CENTRA", "Weight1": 1}]}]
|
||
|
|
|
||
|
|
monkeypatch.setattr(outlook_utilities, "download_attachments", descargar)
|
||
|
|
monkeypatch.setattr(outlook_utilities, "send_email", enviar)
|
||
|
|
monkeypatch.setattr(sapb1_manager, "get_zonas", lambda: [{"Code": "Z1", "Name": "ZONA1"}])
|
||
|
|
monkeypatch.setattr(sapb1_manager, "get_delivery_notes", delivery_notes)
|
||
|
|
monkeypatch.setattr(sapb1_manager, "obtener_condicion_pago", lambda c: {"NumberOfAdditionalDays": 30})
|
||
|
|
monkeypatch.setattr(sapb1_manager, "create_draft", crear_draft)
|
||
|
|
monkeypatch.setattr(hana_manager, "obtener_valor_referencial", lambda s, n: 0.0)
|
||
|
|
|
||
|
|
e.descarga = tmp_path / "descarga"
|
||
|
|
e.salida = tmp_path / "salida"
|
||
|
|
return e
|
||
|
|
|
||
|
|
|
||
|
|
def _procesar(e, sender="proveedor@empresa.com"):
|
||
|
|
email = {"id": "abc", "fecha": "2026-10-14 10:00:00", "subject": "Factura", "sender": sender}
|
||
|
|
pipeline._procesar_un_correo(email, "token", "buzon@aberio.com", str(e.descarga), str(e.salida))
|
||
|
|
return email
|
||
|
|
|
||
|
|
|
||
|
|
def test_precios_coinciden_crea_draft_y_notifica(entorno):
|
||
|
|
_procesar(entorno)
|
||
|
|
|
||
|
|
assert len(entorno.drafts) == 1
|
||
|
|
draft = entorno.drafts[0]
|
||
|
|
assert draft["CardCode"] == "PL10060028686"
|
||
|
|
assert draft["NumAtCard"] == "01F002-2450"
|
||
|
|
assert draft["DocumentLines"][0]["U_IDC_GRFLETE"] == "09T001-128912"
|
||
|
|
|
||
|
|
assert len(entorno.correos) == 1
|
||
|
|
correo = entorno.correos[0]
|
||
|
|
assert correo["para"] == ["proveedor@empresa.com"]
|
||
|
|
assert correo["asunto"] == "Draft SAP B1 - F002-2450"
|
||
|
|
assert "creado exitosamente" in correo["html"] and "777" in correo["html"]
|
||
|
|
assert correo["cc"] # siempre se copia al equipo
|
||
|
|
assert any(a.endswith(".xml") for a in correo["adjuntos"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_precios_no_coinciden_no_crea_draft_pero_notifica(entorno):
|
||
|
|
entorno.line_total_sap = TOTAL_LINEA + 50
|
||
|
|
|
||
|
|
_procesar(entorno)
|
||
|
|
|
||
|
|
assert entorno.drafts == []
|
||
|
|
assert len(entorno.correos) == 1
|
||
|
|
assert "Draft NO creado" in entorno.correos[0]["html"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_error_al_crear_draft_se_notifica(entorno):
|
||
|
|
entorno.error_al_crear = RuntimeError("Service Layer caído")
|
||
|
|
|
||
|
|
_procesar(entorno)
|
||
|
|
|
||
|
|
assert entorno.drafts == []
|
||
|
|
assert len(entorno.correos) == 1
|
||
|
|
assert "Error al crear Draft" in entorno.correos[0]["html"]
|
||
|
|
assert "Service Layer caído" in entorno.correos[0]["html"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_remitente_desconocido_no_envia_correo(entorno):
|
||
|
|
_procesar(entorno, sender="Desconocido")
|
||
|
|
|
||
|
|
assert len(entorno.drafts) == 1 # el draft se crea igual
|
||
|
|
assert entorno.correos == []
|
||
|
|
|
||
|
|
|
||
|
|
def test_correo_ya_procesado_se_salta(entorno, monkeypatch):
|
||
|
|
monkeypatch.setattr(database_utilities, "get_existing_ids", lambda ids: ["abc"])
|
||
|
|
|
||
|
|
_procesar(entorno)
|
||
|
|
|
||
|
|
assert entorno.descargas == 0
|
||
|
|
assert entorno.drafts == [] and entorno.correos == []
|
||
|
|
|
||
|
|
|
||
|
|
def test_guarda_resultados_y_draft_en_disco(entorno):
|
||
|
|
_procesar(entorno)
|
||
|
|
|
||
|
|
nombres = os.listdir(entorno.salida)
|
||
|
|
assert any(n.startswith("xml_resultado_F002-2450") for n in nombres)
|
||
|
|
assert any(n.startswith("draft_sapb1_F002-2450") for n in nombres)
|