diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py index 006d7bc600..74e3088da8 100644 --- a/src/backend/InvenTree/InvenTree/api_version.py +++ b/src/backend/InvenTree/InvenTree/api_version.py @@ -1,12 +1,15 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 365 +INVENTREE_API_VERSION = 366 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v366 -> 2025-07-09 : https://github.com/inventree/InvenTree/pull/9987 + - Adds "category" filter to BomItem API endpoint + v365 -> 2025-07-09 : https://github.com/inventree/InvenTree/pull/9984 - Allow filtering of DataOutput API by "user" field - Allow individual deletion of DataOutput objects via the API diff --git a/src/backend/InvenTree/part/api.py b/src/backend/InvenTree/part/api.py index e9c41248f8..90ee0e5197 100644 --- a/src/backend/InvenTree/part/api.py +++ b/src/backend/InvenTree/part/api.py @@ -1631,10 +1631,24 @@ class BomFilter(rest_filters.FilterSet): queryset=Part.objects.all(), method='filter_part', label=_('Part') ) + @extend_schema_field(OpenApiTypes.INT) def filter_part(self, queryset, name, part): """Filter the queryset based on the specified part.""" return queryset.filter(part.get_bom_item_filter()) + category = rest_filters.ModelChoiceFilter( + queryset=PartCategory.objects.all(), + method='filter_category', + label=_('Category'), + ) + + @extend_schema_field(OpenApiTypes.INT) + def filter_category(self, queryset, name, category): + """Filter the queryset based on the specified PartCategory.""" + cats = category.get_descendants(include_self=True) + + return queryset.filter(sub_part__category__in=cats) + uses = rest_filters.ModelChoiceFilter( queryset=Part.objects.all(), method='filter_uses', label=_('Uses') ) diff --git a/src/frontend/src/tables/Filter.tsx b/src/frontend/src/tables/Filter.tsx index 627600644e..4a0edc6cc7 100644 --- a/src/frontend/src/tables/Filter.tsx +++ b/src/frontend/src/tables/Filter.tsx @@ -343,7 +343,7 @@ export function IssuedByFilter(): TableFilter { export function PartCategoryFilter(): TableFilter { return { name: 'category', - label: t`Category`, + label: t`Part Category`, description: t`Filter by part category`, apiUrl: apiUrl(ApiEndpoints.category_list), model: ModelType.partcategory, diff --git a/src/frontend/src/tables/bom/BomTable.tsx b/src/frontend/src/tables/bom/BomTable.tsx index 0d9686b7c3..46f0600a7d 100644 --- a/src/frontend/src/tables/bom/BomTable.tsx +++ b/src/frontend/src/tables/bom/BomTable.tsx @@ -42,6 +42,7 @@ import { NoteColumn, ReferenceColumn } from '../ColumnRenderers'; +import { PartCategoryFilter } from '../Filter'; import { InvenTreeTable } from '../InvenTreeTable'; import { type RowAction, RowDeleteAction, RowEditAction } from '../RowActions'; import { TableHoverCard } from '../TableHoverCard'; @@ -369,7 +370,8 @@ export function BomTable({ name: 'has_pricing', label: t`Has Pricing`, description: t`Show items with pricing` - } + }, + PartCategoryFilter() ]; }, [partId, params]); diff --git a/src/frontend/tests/pages/pui_build.spec.ts b/src/frontend/tests/pages/pui_build.spec.ts index 25c8e0b458..f22248b9a4 100644 --- a/src/frontend/tests/pages/pui_build.spec.ts +++ b/src/frontend/tests/pages/pui_build.spec.ts @@ -109,7 +109,9 @@ test('Build Order - Calendar', async ({ browser }) => { await page.getByLabel('calendar-select-filters').click(); await page.getByRole('button', { name: 'Add Filter' }).click(); await page.getByPlaceholder('Select filter').fill('category'); - await page.getByRole('option', { name: 'Category', exact: true }).click(); + await page + .getByRole('option', { name: 'Part Category', exact: true }) + .click(); await page.getByLabel('related-field-filter-category').click(); await page.getByText('Part category, level 1').waitFor();