feat: extract workflow notifications phase 3

This commit is contained in:
2026-04-07 09:57:39 +02:00
parent 160c198bb3
commit 98b3eadcb2
6 changed files with 291 additions and 63 deletions
@@ -17,12 +17,14 @@ from app.domains.products.models import CadFile, Product
from app.domains.rendering.models import OutputType, RenderTemplate
from app.domains.rendering.workflow_runtime_services import (
auto_populate_materials_for_cad,
emit_order_line_render_notifications,
persist_order_line_output,
resolve_cad_bbox,
prepare_order_line_render_context,
resolve_order_line_material_map,
resolve_order_line_template_context,
)
from app.domains.tenants.models import Tenant
import app.models # noqa: F401
@@ -543,3 +545,178 @@ def test_persist_order_line_output_marks_failure_without_result_path(sync_sessio
assert line.result_path is None
assert line.render_log == {"error": "boom"}
assert assets == []
def test_emit_order_line_render_notifications_emits_websocket_and_activity(
sync_session,
tmp_path,
):
line = _seed_order_line_graph(sync_session, tmp_path)
tenant = Tenant(name="Workflow Tenant", slug=f"workflow-{uuid.uuid4().hex[:8]}")
sync_session.add(tenant)
sync_session.commit()
line.product.cad_file.tenant_id = tenant.id
line.product.tenant_id = tenant.id
line.order.tenant_id = tenant.id
sync_session.commit()
websocket_events: list[tuple[str, dict]] = []
activity_events: list[dict] = []
def _capture_websocket(tenant_id: str, event: dict) -> None:
websocket_events.append((tenant_id, event))
def _capture_activity(**payload) -> None:
activity_events.append(payload)
monkeypatch = pytest.MonkeyPatch()
monkeypatch.setattr(
"app.core.websocket.publish_event_sync",
_capture_websocket,
)
monkeypatch.setattr(
"app.services.notification_service.emit_notification_sync",
_capture_activity,
)
try:
emit_order_line_render_notifications(
success=True,
order_line_id=str(line.id),
tenant_id=str(tenant.id),
product_name=line.product.name or "product",
output_type_name=line.output_type.name,
session=sync_session,
line=line,
)
finally:
monkeypatch.undo()
assert websocket_events == [
(
str(tenant.id),
{
"type": "render_complete",
"order_line_id": str(line.id),
"order_id": str(line.order_id),
"status": "completed",
},
)
]
assert activity_events == [
{
"actor_user_id": None,
"target_user_id": str(line.order.created_by),
"action": "render.completed",
"entity_type": "order",
"entity_id": str(line.order_id),
"details": {
"order_number": line.order.order_number,
"product_name": line.product.name,
"output_type": line.output_type.name,
},
"channel": "activity",
}
]
def test_emit_order_line_render_notifications_truncates_failure_error_and_skips_websocket_without_tenant(
sync_session,
tmp_path,
):
line = _seed_order_line_graph(sync_session, tmp_path)
activity_events: list[dict] = []
websocket_events: list[tuple[str, dict]] = []
def _capture_websocket(tenant_id: str, event: dict) -> None:
websocket_events.append((tenant_id, event))
def _capture_activity(**payload) -> None:
activity_events.append(payload)
monkeypatch = pytest.MonkeyPatch()
monkeypatch.setattr(
"app.core.websocket.publish_event_sync",
_capture_websocket,
)
monkeypatch.setattr(
"app.services.notification_service.emit_notification_sync",
_capture_activity,
)
try:
emit_order_line_render_notifications(
success=False,
order_line_id=str(line.id),
product_name=line.product.name or "product",
output_type_name=line.output_type.name,
render_log={"error": "x" * 400},
session=sync_session,
line=line,
)
finally:
monkeypatch.undo()
assert websocket_events == []
assert activity_events == [
{
"actor_user_id": None,
"target_user_id": str(line.order.created_by),
"action": "render.failed",
"entity_type": "order",
"entity_id": str(line.order_id),
"details": {
"order_number": line.order.order_number,
"product_name": line.product.name,
"output_type": line.output_type.name,
"error": "x" * 300,
},
"channel": "activity",
}
]
def test_emit_order_line_render_notifications_supports_retry_exhausted_activity_payload():
activity_events: list[dict] = []
def _capture_activity(**payload) -> None:
activity_events.append(payload)
monkeypatch = pytest.MonkeyPatch()
monkeypatch.setattr(
"app.services.notification_service.emit_notification_sync",
_capture_activity,
)
try:
emit_order_line_render_notifications(
success=False,
order_line_id="line-1",
order_number="ORD-FAIL",
order_creator_id="user-1",
product_name="unknown",
output_type_name="unknown",
render_log={"error": "retry exhausted"},
emit_websocket=False,
activity_entity_id=None,
)
finally:
monkeypatch.undo()
assert activity_events == [
{
"actor_user_id": None,
"target_user_id": "user-1",
"action": "render.failed",
"entity_type": "order",
"entity_id": None,
"details": {
"order_number": "ORD-FAIL",
"product_name": "unknown",
"output_type": "unknown",
"error": "retry exhausted",
},
"channel": "activity",
}
]