2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 11:36:44 +00:00

Build category filter (#8940)

* Add 'category' filter to BuildList

- Allows filtering by part category

* Add filter element to build table

* Bump API version
This commit is contained in:
Oliver 2025-01-22 22:22:03 +11:00 committed by GitHub
parent 19d7825fa6
commit e9bc4645ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 61 additions and 17 deletions

View File

@ -1,36 +1,39 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 303 INVENTREE_API_VERSION = 304
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" """Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """ INVENTREE_API_TEXT = """
v303 - 2025-01-20 - https://github.com/inventree/InvenTree/pull/8915 v304 - 2025-01-22 : https://github.com/inventree/InvenTree/pull/8940
- Adds "category" filter to build list API
v303 - 2025-01-20 : https://github.com/inventree/InvenTree/pull/8915
- Adds "start_date" field to Build model and API endpoints - Adds "start_date" field to Build model and API endpoints
- Adds additional API filtering and sorting options for Build list - Adds additional API filtering and sorting options for Build list
v302 - 2025-01-18 - https://github.com/inventree/InvenTree/pull/8905 v302 - 2025-01-18 : https://github.com/inventree/InvenTree/pull/8905
- Fix schema definition on the /label/print endpoint - Fix schema definition on the /label/print endpoint
v301 - 2025-01-14 - https://github.com/inventree/InvenTree/pull/8894 v301 - 2025-01-14 : https://github.com/inventree/InvenTree/pull/8894
- Remove ui preferences from the API - Remove ui preferences from the API
v300 - 2025-01-13 - https://github.com/inventree/InvenTree/pull/8886 v300 - 2025-01-13 : https://github.com/inventree/InvenTree/pull/8886
- Allow null value for 'expiry_date' field introduced in #8867 - Allow null value for 'expiry_date' field introduced in #8867
v299 - 2025-01-10 - https://github.com/inventree/InvenTree/pull/8867 v299 - 2025-01-10 : https://github.com/inventree/InvenTree/pull/8867
- Adds 'expiry_date' field to the PurchaseOrderReceive API endpoint - Adds 'expiry_date' field to the PurchaseOrderReceive API endpoint
- Adds 'default_expiry` field to the PartBriefSerializer, affecting API endpoints which use it - Adds 'default_expiry` field to the PartBriefSerializer, affecting API endpoints which use it
v298 - 2025-01-07 - https://github.com/inventree/InvenTree/pull/8848 v298 - 2025-01-07 : https://github.com/inventree/InvenTree/pull/8848
- Adds 'created_by' field to PurchaseOrder API endpoints - Adds 'created_by' field to PurchaseOrder API endpoints
- Adds 'created_by' field to SalesOrder API endpoints - Adds 'created_by' field to SalesOrder API endpoints
- Adds 'created_by' field to ReturnOrder API endpoints - Adds 'created_by' field to ReturnOrder API endpoints
v297 - 2024-12-29 - https://github.com/inventree/InvenTree/pull/8438 v297 - 2024-12-29 : https://github.com/inventree/InvenTree/pull/8438
- Adjustments to the CustomUserState API endpoints and serializers - Adjustments to the CustomUserState API endpoints and serializers
v296 - 2024-12-25 : https://github.com/inventree/InvenTree/pull/8732 v296 - 2024-12-25 : https://github.com/inventree/InvenTree/pull/8732

View File

@ -13,7 +13,7 @@ from rest_framework.exceptions import ValidationError
import build.admin import build.admin
import build.serializers import build.serializers
import common.models import common.models
import part.models import part.models as part_models
from build.models import Build, BuildItem, BuildLine from build.models import Build, BuildItem, BuildLine
from build.status_codes import BuildStatus, BuildStatusGroups from build.status_codes import BuildStatus, BuildStatusGroups
from generic.states.api import StatusView from generic.states.api import StatusView
@ -77,7 +77,10 @@ class BuildFilter(rest_filters.FilterSet):
return queryset return queryset
part = rest_filters.ModelChoiceFilter( part = rest_filters.ModelChoiceFilter(
queryset=part.models.Part.objects.all(), field_name='part', method='filter_part' queryset=part_models.Part.objects.all(),
field_name='part',
method='filter_part',
label=_('Part'),
) )
def filter_part(self, queryset, name, part): def filter_part(self, queryset, name, part):
@ -94,6 +97,17 @@ class BuildFilter(rest_filters.FilterSet):
else: else:
return queryset.filter(part=part) return queryset.filter(part=part)
category = rest_filters.ModelChoiceFilter(
queryset=part_models.PartCategory.objects.all(),
method='filter_category',
label=_('Category'),
)
def filter_category(self, queryset, name, category):
"""Filter by part category (including sub-categories)."""
categories = category.get_descendants(include_self=True)
return queryset.filter(part__category__in=categories)
ancestor = rest_filters.ModelChoiceFilter( ancestor = rest_filters.ModelChoiceFilter(
queryset=Build.objects.all(), queryset=Build.objects.all(),
label=_('Ancestor Build'), label=_('Ancestor Build'),
@ -417,7 +431,7 @@ class BuildLineFilter(rest_filters.FilterSet):
) )
part = rest_filters.ModelChoiceFilter( part = rest_filters.ModelChoiceFilter(
queryset=part.models.Part.objects.all(), queryset=part_models.Part.objects.all(),
label=_('Part'), label=_('Part'),
field_name='bom_item__sub_part', field_name='bom_item__sub_part',
) )
@ -729,7 +743,7 @@ class BuildItemFilter(rest_filters.FilterSet):
return queryset return queryset
part = rest_filters.ModelChoiceFilter( part = rest_filters.ModelChoiceFilter(
queryset=part.models.Part.objects.all(), queryset=part_models.Part.objects.all(),
label=_('Part'), label=_('Part'),
method='filter_part', method='filter_part',
field_name='stock_item__part', field_name='stock_item__part',

View File

@ -179,10 +179,17 @@ function FilterAddGroup({
// Determine the "type" of filter (default = boolean) // Determine the "type" of filter (default = boolean)
const filterType: TableFilterType = useMemo(() => { const filterType: TableFilterType = useMemo(() => {
return ( const filter = availableFilters?.find((flt) => flt.name === selectedFilter);
availableFilters?.find((flt) => flt.name === selectedFilter)?.type ??
'boolean' if (filter?.type) {
); return filter.type;
} else if (filter?.choices) {
// If choices are provided, it is a choice filter
return 'choice';
} else {
// Default fallback
return 'boolean';
}
}, [selectedFilter]); }, [selectedFilter]);
const setSelectedValue = useCallback( const setSelectedValue = useCallback(

View File

@ -8,7 +8,9 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { useBuildOrderFields } from '../../forms/BuildForms'; import { useBuildOrderFields } from '../../forms/BuildForms';
import { shortenString } from '../../functions/tables';
import { import {
useFilters,
useOwnerFilters, useOwnerFilters,
useProjectCodeFilters, useProjectCodeFilters,
useUserFilters useUserFilters
@ -131,6 +133,17 @@ export function BuildOrderTable({
const ownerFilters = useOwnerFilters(); const ownerFilters = useOwnerFilters();
const userFilters = useUserFilters(); const userFilters = useUserFilters();
const categoryFilters = useFilters({
url: apiUrl(ApiEndpoints.category_list),
transform: (item) => ({
value: item.pk,
label: shortenString({
str: item.pathstring,
len: 50
})
})
});
const tableFilters: TableFilter[] = useMemo(() => { const tableFilters: TableFilter[] = useMemo(() => {
const filters: TableFilter[] = [ const filters: TableFilter[] = [
OutstandingFilter(), OutstandingFilter(),
@ -177,7 +190,13 @@ export function BuildOrderTable({
description: t`Filter by user who issued this order`, description: t`Filter by user who issued this order`,
choices: userFilters.choices choices: userFilters.choices
}, },
ResponsibleFilter({ choices: ownerFilters.choices }) ResponsibleFilter({ choices: ownerFilters.choices }),
{
name: 'category',
label: t`Category`,
description: t`Filter by part category`,
choices: categoryFilters.choices
}
]; ];
// If we are filtering on a specific part, we can include the "include variants" filter // If we are filtering on a specific part, we can include the "include variants" filter
@ -193,6 +212,7 @@ export function BuildOrderTable({
return filters; return filters;
}, [ }, [
partId, partId,
categoryFilters.choices,
projectCodeFilters.choices, projectCodeFilters.choices,
ownerFilters.choices, ownerFilters.choices,
userFilters.choices userFilters.choices