A slot mapped to a different filament than it was sliced for (PLA slice
routed to the only loaded PETG slot) was logged under the sliced material
in the archive, Print Log and material stats, even though the correct spool
was debited. Once usage tracking resolves every used slot to a spool, adopt
the spool's material as the archive filament_type, exactly as the spool
colour is already adopted (#1494). All-or-nothing; both inventory backends;
flows through to the Print Log and stats. No schema/UI/i18n change.
When a print targets a single plate from a multi-plate 3MF, both the
internal Filament Inventory tracker and the Spoolman-mode tracker parsed
the 3MF without a plate filter and summed every plate's filament — so a
single lid print debited the spool the entire file's grey + black totals.
The 3MF parser already supports plate_id (queue pre-flight uses it at
print_queue.py:254/:286). Plumbed it through both dispatch paths:
Queue path:
- PrintSession gains a plate_id field; on_print_start queries the
printer's currently-printing queue row and records queue_item.plate_id
onto the session.
- _track_from_3mf accepts plate_id and passes it to the extractor.
- store_print_data moves its existing queue-item lookup above the
extract and uses queue_item.plate_id as the plate filter.
Direct-Print path (reprintArchive / printLibraryFile — never goes
through the queue):
- _print_plate_ids dict added in main.py, parallel to _print_ams_mappings.
- register_expected_print accepts plate_id and stores it; the 2 sites in
background_dispatch.py and the 1 site in print_scheduler.py now pass
it (resolve was already happening, just needed reordering before the
register call so the value is available).
- Expected-print promotion in main.py injects _print_plate_ids[archive_id]
into the session, guarded so a queue capture wins over the dict.
- _get_start_plate_id helper feeds plate_id into all 3
_store_spoolman_print_data call sites; spoolman_tracking.store_print_data
takes the caller value first, falls back to queue_item.plate_id.
PrintArchive.filament_used_grams stays file-level summed by design
(#1593's contract — the archive describes the file, not the run); only
the per-run usage attribution becomes plate-aware. Single-plate direct
prints resolve to plate_id=1 → plate 1 = whole file, identical to the
prior no-filter behaviour.
feat(spoolman-inventory): squashed feature work for rebase onto dev
Squashed all commits from feature/spoolman-inventory-ui onto a single commit
to enable a clean rebase onto dev. Original per-commit history preserved at
backup tag backup/spoolman-inventory-ui-prerebase-20260507-105721.
feat(spoolman-inventory): squashed feature work for rebase onto dev
Squashed all commits from feature/spoolman-inventory-ui onto a single commit
to enable a clean rebase onto dev. Original per-commit history preserved at
backup tag backup/spoolman-inventory-ui-prerebase-20260507-105721.
feat(inventory): replace Spoolman iframe with internal inventory UI
When Spoolman is enabled, the Inventory page now uses the same internal
UI (spool list, create/edit modal, archive, delete, weight sync) backed
by a new proxy layer instead of opening an iframe.