diff --git a/client/src/pages/home/index.tsx b/client/src/pages/home/index.tsx index e33891b..e0d2acd 100644 --- a/client/src/pages/home/index.tsx +++ b/client/src/pages/home/index.tsx @@ -60,20 +60,14 @@ export const Home: React.FC = () => { ).length; }, [spoolsResult?.data]); - // For accurate low stock count, we need all spools + // For accurate low stock count, we need all spools with remaining_weight < threshold const { result: lowStockResult } = useList({ resource: "spool", pagination: { pageSize: 1000 }, - filters: [ - { - field: "remaining_weight", - operator: "lt", - value: LOW_STOCK_THRESHOLD, - }, - ], meta: { queryParams: { allow_archived: false, + remaining_weight_lt: LOW_STOCK_THRESHOLD, }, }, }); diff --git a/spoolman/api/v1/spool.py b/spoolman/api/v1/spool.py index aa91283..cae8bba 100644 --- a/spoolman/api/v1/spool.py +++ b/spoolman/api/v1/spool.py @@ -268,6 +268,20 @@ async def find( Optional[bool], Query(title="Needs Weighing", description="Filter by spools that need manual weigh-in."), ] = None, + remaining_weight_lt: Annotated[ + Optional[float], + Query( + title="Remaining Weight Less Than", + description="Filter by spools with remaining weight (in grams) less than this value.", + ), + ] = None, + remaining_weight_gt: Annotated[ + Optional[float], + Query( + title="Remaining Weight Greater Than", + description="Filter by spools with remaining weight (in grams) greater than this value.", + ), + ] = None, sort: Annotated[ Optional[str], Query( @@ -313,6 +327,8 @@ async def find( lot_nr=lot_nr, allow_archived=allow_archived, needs_weighing=needs_weighing, + remaining_weight_lt=remaining_weight_lt, + remaining_weight_gt=remaining_weight_gt, sort_by=sort_by, limit=limit, offset=offset, diff --git a/spoolman/database/spool.py b/spoolman/database/spool.py index 744c9d5..d975ca4 100644 --- a/spoolman/database/spool.py +++ b/spoolman/database/spool.py @@ -124,6 +124,8 @@ async def find( # noqa: C901, PLR0912 lot_nr: Optional[str] = None, allow_archived: bool = False, needs_weighing: Optional[bool] = None, + remaining_weight_lt: Optional[float] = None, + remaining_weight_gt: Optional[float] = None, sort_by: Optional[dict[str, SortOrder]] = None, limit: Optional[int] = None, offset: int = 0, @@ -170,6 +172,13 @@ async def find( # noqa: C901, PLR0912 ), ) + # Filter by remaining_weight (computed as initial_weight - used_weight, falling back to filament.weight) + remaining_weight_expr = coalesce(models.Spool.initial_weight, models.Filament.weight) - models.Spool.used_weight + if remaining_weight_lt is not None: + stmt = stmt.where(remaining_weight_expr < remaining_weight_lt) + if remaining_weight_gt is not None: + stmt = stmt.where(remaining_weight_expr > remaining_weight_gt) + total_count = None if limit is not None: