From 7054fa4b4056180cd2efb0bc4213d7ec6233b5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hartmut=20N=C3=B6renberg?= Date: Fri, 13 Mar 2026 15:28:39 +0100 Subject: [PATCH] fix: skip render for cancelled order lines and rejected orders Adds early-exit checks in dispatch_order_line_render and render_order_line_task to prevent rendering when order lines are cancelled or the parent order is rejected/completed. Co-Authored-By: Claude Opus 4.6 --- .../pipeline/tasks/render_order_line.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/backend/app/domains/pipeline/tasks/render_order_line.py b/backend/app/domains/pipeline/tasks/render_order_line.py index 1b147a6..d8e9adb 100644 --- a/backend/app/domains/pipeline/tasks/render_order_line.py +++ b/backend/app/domains/pipeline/tasks/render_order_line.py @@ -16,6 +16,30 @@ logger = logging.getLogger(__name__) @celery_app.task(name="app.tasks.step_tasks.dispatch_order_line_render", queue="step_processing") def dispatch_order_line_render(order_line_id: str): """Route an order-line render to render_order_line_task.""" + # Pre-check: skip if line is already cancelled or order is rejected + from sqlalchemy import create_engine, select + from sqlalchemy.orm import Session + from app.config import settings as app_settings + from app.models.order_line import OrderLine + from app.domains.orders.models import Order, OrderStatus + + sync_url = app_settings.database_url.replace("+asyncpg", "") + engine = create_engine(sync_url) + with Session(engine) as session: + line = session.execute( + select(OrderLine).where(OrderLine.id == order_line_id) + ).scalar_one_or_none() + if line and line.render_status == "cancelled": + logger.info(f"OrderLine {order_line_id} cancelled — not dispatching") + return + if line: + order = session.execute( + select(Order).where(Order.id == line.order_id) + ).scalar_one_or_none() + if order and order.status in (OrderStatus.rejected, OrderStatus.completed): + logger.info(f"OrderLine {order_line_id}: order {order.status.value} — not dispatching") + return + logger.info(f"Dispatching render for order line: {order_line_id}") render_order_line_task.delay(order_line_id) @@ -67,6 +91,28 @@ def render_order_line_task(self, order_line_id: str): logger.error(f"OrderLine {order_line_id} not found") return + # Skip if line was cancelled or order was rejected/completed + if line.render_status == "cancelled": + emit(order_line_id, "Order line already cancelled — skipping render") + logger.info(f"OrderLine {order_line_id} cancelled — skipping") + return + + from app.domains.orders.models import Order, OrderStatus + order = session.execute( + select(Order).where(Order.id == line.order_id) + ).scalar_one_or_none() + if order and order.status in (OrderStatus.rejected, OrderStatus.completed): + emit(order_line_id, f"Order {order.status.value} — skipping render") + logger.info(f"OrderLine {order_line_id}: order {order.status.value} — skipping") + if line.render_status in ("pending", "processing"): + session.execute( + sql_update(OrderLine) + .where(OrderLine.id == line.id) + .values(render_status="cancelled") + ) + session.commit() + return + if line.product.cad_file_id is None: emit(order_line_id, "Product has no CAD file — marking as failed", "error") logger.warning(f"OrderLine {order_line_id}: product has no CAD file")