Pool AMS backup spools in the print dialog's filament check

The dialog weighed each plate against the spool in the slot it mapped to
and knew nothing about AMS Filament Backup, so a two-plate job needing
1441 g of ABS was refused against a 1000 g spool while the identical full
spool in the next slot went uncounted. The dispatcher has pooled matching
spools since #1762 and would have run the print -- "Print anyway" was
always the right answer to this warning.

The rule for which spools back each other up now lives in one place:
build_slot_materials() in filament_deficit, which the dispatcher's pool
and the new slot_materials half of GET /printers/{id}/inventory-remain
both draw on. The dialog groups on the keys it is handed rather than
resolving spools a second time, which is what let the two answers drift
apart, and which also gives the check to Spoolman users -- it read the
internal inventory only, so in Spoolman mode it approved everything.

Where a pool really is short the warning quotes the pooled totals, since
the per-slot figure reads as a contradiction next to a full peer spool.
This commit is contained in:
maziggy
2026-08-11 11:32:17 +02:00
parent e93f1b43c3
commit df5aa04df1
24 changed files with 672 additions and 136 deletions
+22 -1
View File
@@ -3465,6 +3465,27 @@ export interface SpoolKProfileInput {
setting_id?: string | null;
}
/** One inventory-bound AMS slot, as returned by `/printers/{id}/inventory-remain`. */
export interface SlotMaterial {
ams_id: number;
tray_id: number;
global_tray_id: number;
/** Opaque grouping key from the backend. Two slots back each other up under
* AMS Filament Backup only when both `material_key` and `extruder` match.
* Never parse it — the format belongs to the backend's identity rule. */
material_key: string;
remaining_g: number;
/** 0 = right / single nozzle, 1 = left. */
extruder: number;
}
export interface InventoryRemainResponse {
/** Currently-loaded, inventory-bound slots only — drives the prefer-lowest sort. */
inventory_remain_g: Record<string, number>;
/** Every inventory binding on the printer, with identity + extruder side. */
slot_materials: SlotMaterial[];
}
export interface SpoolAssignment {
id: number;
spool_id: number;
@@ -4503,7 +4524,7 @@ export const api = {
// when computing the AMS mapping; mirrors backend `_build_inventory_remain_overrides`
// so internal and Spoolman modes both work uniformly.
getInventoryRemain: (printerId: number) =>
request<{ inventory_remain_g: Record<string, number> }>(
request<InventoryRemainResponse>(
`/printers/${printerId}/inventory-remain`,
),