Browse Source

Fix "Queue to Any Printer" ignoring filament color override (#486)

When scheduling a print to "any printer" with a filament color override,
the scheduler picked a printer with the correct filament type but wrong
color. _find_idle_printer_for_model() used color matching only for
ranking candidates, not filtering — a printer with 0 color matches was
still selected if it had the right types.

Now requires at least 1 color match when filament overrides specify
colors. Printers with 0 matches are skipped and reported in the
"waiting for filament" reason instead of being treated as candidates.
maziggy 6 months ago
parent
commit
c770f842f2
2 changed files with 9 additions and 2 deletions
  1. 1 0
      CHANGELOG.md
  2. 8 2
      backend/app/services/print_scheduler.py

+ 1 - 0
CHANGELOG.md

@@ -10,6 +10,7 @@ All notable changes to Bambuddy will be documented in this file.
 - **"Power Off Printer" Option Not Gated by Control Permission** ([#500](https://github.com/maziggy/bambuddy/issues/500)) — The "Power off printer when done" checkbox in the print modal and the auto power off toggle in the bulk edit modal were accessible to all users regardless of permissions. Users without the `printers:control` permission can now no longer enable auto power off — the checkbox and tri-state toggle are disabled and visually dimmed.
 - **Created Admin Users Can't See Settings Button** ([#503](https://github.com/maziggy/bambuddy/issues/503)) — The sidebar hid the Settings link based on a hardcoded `role === 'user'` check instead of the actual `settings:read` permission, so newly created admin users who had the permission still couldn't see the button. Also, after login the auth state was set directly from the login response instead of re-fetching the full auth status, which could miss permission data. Now uses `hasPermission('settings:read')` for the sidebar check and calls `checkAuthStatus()` after login to load the complete user state including permissions.
 - **"Open in Slicer" Fails for Filenames Containing Special Characters** — Filenames with `/`, `\`, `?`, or `#` (e.g., `Abzweigdose/Verteilerdose 70mm`) caused the slicer protocol handler to fail. The filename is placed in the download URL path and `encodeURIComponent`-encoded, but BambuStudio and OrcaSlicer call `url_decode()` on the entire protocol handler URL before downloading. This decoded `%2F` back to `/`, creating extra path segments that resulted in a 404. The URL filename is purely cosmetic (the backend resolves files by archive ID, not filename), so now sanitizes `/`, `\`, `?`, and `#` to `_` in slicer download URLs.
+- **"Queue to Any Printer" Ignores Filament Color Override** ([#486](https://github.com/maziggy/bambuddy/issues/486)) — When scheduling a print to "any printer" with a filament color override, the scheduler picked a printer with the correct filament type but wrong color. `_find_idle_printer_for_model()` validated only filament type (via `_get_missing_filament_types()`), while color matching (`_count_override_color_matches()`) was used only for ranking candidates, not filtering them. A printer with 0 color matches was still selected if it had the right types. Now requires at least 1 color match when filament overrides specify colors — printers with 0 matches are skipped and added to the "waiting for filament" reason instead of being treated as valid candidates.
 
 ## [0.2.1b3] - 2026-02-23
 

+ 8 - 2
backend/app/services/print_scheduler.py

@@ -320,10 +320,16 @@ class PrintScheduler:
                     logger.debug("Skipping printer %s (%s) - missing filaments: %s", printer.id, printer.name, missing)
                     continue
 
-            # If filament overrides with colors, prefer printers with exact color matches
+            # If filament overrides with colors, only consider printers that have at least one color match
             if filament_overrides:
                 color_matches = self._count_override_color_matches(printer.id, filament_overrides)
-                candidates.append((printer.id, color_matches))
+                if color_matches > 0:
+                    candidates.append((printer.id, color_matches))
+                else:
+                    override_colors = [f"{o.get('type', '?')} ({o.get('color', '?')})" for o in filament_overrides]
+                    printers_missing_filament.append((printer.name, override_colors))
+                    logger.debug("Skipping printer %s (%s) - no matching override colors", printer.id, printer.name)
+                    continue
             else:
                 # No overrides - take first available (existing behavior)
                 return printer.id, None