Bläddra i källkod

fix: resolve printer model server-side for "Any Model" queue items (#435)

The previous fix passed target_model from the frontend, but this relied
on printer.model being set on the client. When a printer was added
without selecting a model (the field is optional), the frontend sent no
target_model parameter, causing the OR logic to be bypassed entirely —
the widget only queried printer_id=X and missed unassigned model-based
items.

The backend now looks up the printer's model from the database when
target_model isn't provided by the client, ensuring "Clear Plate &
Start Next" appears for model-based queue jobs regardless of how the
printer was configured.
maziggy 6 månader sedan
förälder
incheckning
732ff634fa
2 ändrade filer med 24 tillägg och 13 borttagningar
  1. 1 1
      CHANGELOG.md
  2. 23 12
      backend/app/api/routes/print_queue.py

+ 1 - 1
CHANGELOG.md

@@ -5,7 +5,7 @@ All notable changes to Bambuddy will be documented in this file.
 ## [0.2.1b2] - Unreleased
 ## [0.2.1b2] - Unreleased
 
 
 ### Fixed
 ### Fixed
-- **Queue Stuck on "Busy" for "Any Model" Jobs** ([#435](https://github.com/maziggy/bambuddy/issues/435)) — When a print was queued with "Any [Model]" (e.g., "Any P1S"), it was created with `printer_id=NULL` and `target_model="P1S"`. After the assigned printer finished, the queue widget queried only for items matching `printer_id=X`, missing the next pending model-based item (`printer_id IS NULL`). With no next item found, the "Clear Plate & Start Next" button never appeared, leaving the scheduler stuck reporting "Busy". The queue API now accepts an optional `target_model` parameter; when combined with `printer_id`, it uses OR logic to also return unassigned items whose `target_model` matches the printer's model. The frontend passes the printer's model through to this query.
+- **Queue Stuck on "Busy" for "Any Model" Jobs** ([#435](https://github.com/maziggy/bambuddy/issues/435)) — When a print was queued with "Any [Model]" (e.g., "Any P1S"), it was created with `printer_id=NULL` and `target_model="P1S"`. After the assigned printer finished, the queue widget queried only for items matching `printer_id=X`, missing the next pending model-based item (`printer_id IS NULL`). With no next item found, the "Clear Plate & Start Next" button never appeared, leaving the scheduler stuck reporting "Busy". The queue API now accepts an optional `target_model` parameter; when combined with `printer_id`, it uses OR logic to also return unassigned items whose `target_model` matches the printer's model. The frontend passes the printer's model through to this query. Additionally, the backend now resolves the printer's model server-side from the database when the frontend doesn't provide `target_model` (e.g., when the printer was added without selecting a model), ensuring the OR logic works regardless of whether the client knows the printer's model.
 
 
 ### New Features
 ### New Features
 - **Include Beta Updates Setting** — New toggle in Settings → Updates to opt in to beta/prerelease update notifications. Default: off (stable only). The update checker now fetches `/releases` instead of `/releases/latest` and filters by `parse_version()` prerelease detection (not GitHub's `prerelease` flag, which may not be set correctly). Users on the Docker `latest` tag will no longer see notifications for beta releases they can't install.
 - **Include Beta Updates Setting** — New toggle in Settings → Updates to opt in to beta/prerelease update notifications. Default: off (stable only). The update checker now fetches `/releases` instead of `/releases/latest` and filters by `parse_version()` prerelease detection (not GitHub's `prerelease` flag, which may not be set correctly). Users on the Docker `latest` tag will no longer see notifications for beta releases they can't install.

+ 23 - 12
backend/app/api/routes/print_queue.py

@@ -270,19 +270,30 @@ async def list_queue(
         if printer_id == -1:
         if printer_id == -1:
             # Special value: filter for unassigned items
             # Special value: filter for unassigned items
             query = query.where(PrintQueueItem.printer_id.is_(None))
             query = query.where(PrintQueueItem.printer_id.is_(None))
-        elif target_model:
-            # Include both printer-specific items AND model-based (unassigned) items
-            query = query.where(
-                or_(
-                    PrintQueueItem.printer_id == printer_id,
-                    and_(
-                        PrintQueueItem.printer_id.is_(None),
-                        func.lower(PrintQueueItem.target_model) == target_model.lower(),
-                    ),
-                )
-            )
         else:
         else:
-            query = query.where(PrintQueueItem.printer_id == printer_id)
+            # Resolve effective model: prefer explicit param, fall back to printer's DB model.
+            # This ensures model-based "Any X" items are returned even when the frontend
+            # doesn't send target_model (e.g. printer.model is NULL on the client side).
+            effective_model = target_model
+            if not effective_model:
+                printer_row = (
+                    await db.execute(select(Printer.model).where(Printer.id == printer_id))
+                ).scalar_one_or_none()
+                effective_model = printer_row
+
+            if effective_model:
+                # Include both printer-specific items AND model-based (unassigned) items
+                query = query.where(
+                    or_(
+                        PrintQueueItem.printer_id == printer_id,
+                        and_(
+                            PrintQueueItem.printer_id.is_(None),
+                            func.lower(PrintQueueItem.target_model) == effective_model.lower(),
+                        ),
+                    )
+                )
+            else:
+                query = query.where(PrintQueueItem.printer_id == printer_id)
     elif target_model:
     elif target_model:
         query = query.where(func.lower(PrintQueueItem.target_model) == target_model.lower())
         query = query.where(func.lower(PrintQueueItem.target_model) == target_model.lower())
     if status:
     if status: