Improve "issued by" filter for Build list API (#7900)

* Simplify build order filters

* Improve labels for order filters

* Bump API version
This commit is contained in:
Oliver 2024-08-16 19:56:43 +10:00 committed by GitHub
parent ed2ac0f1da
commit 7178b95657
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 63 additions and 60 deletions

View File

@ -1,13 +1,17 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 239 INVENTREE_API_VERSION = 240
"""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 = """
v240 - 2024-08-16 : https://github.com/inventree/InvenTree/pull/7900
- Adjust "issued_by" filter for the BuildOrder list endpoint
- Adjust "assigned_to" filter for the BuildOrder list endpoint
v239 - 2024-08-15 : https://github.com/inventree/InvenTree/pull/7888 v239 - 2024-08-15 : https://github.com/inventree/InvenTree/pull/7888
- Adds "testable" field to the Part model - Adds "testable" field to the Part model
- Adds associated filters to various API endpoints - Adds associated filters to various API endpoints

View File

@ -37,7 +37,6 @@ class BuildFilter(rest_filters.FilterSet):
'parent', 'parent',
'sales_order', 'sales_order',
'part', 'part',
'issued_by',
] ]
status = rest_filters.NumberFilter(label='Status') status = rest_filters.NumberFilter(label='Status')
@ -58,7 +57,10 @@ class BuildFilter(rest_filters.FilterSet):
return queryset.filter(Build.OVERDUE_FILTER) return queryset.filter(Build.OVERDUE_FILTER)
return queryset.exclude(Build.OVERDUE_FILTER) return queryset.exclude(Build.OVERDUE_FILTER)
assigned_to_me = rest_filters.BooleanFilter(label='assigned_to_me', method='filter_assigned_to_me') assigned_to_me = rest_filters.BooleanFilter(
label=_('Assigned to me'),
method='filter_assigned_to_me'
)
def filter_assigned_to_me(self, queryset, name, value): def filter_assigned_to_me(self, queryset, name, value):
"""Filter by orders which are assigned to the current user.""" """Filter by orders which are assigned to the current user."""
@ -71,10 +73,33 @@ class BuildFilter(rest_filters.FilterSet):
return queryset.filter(responsible__in=owners) return queryset.filter(responsible__in=owners)
return queryset.exclude(responsible__in=owners) return queryset.exclude(responsible__in=owners)
assigned_to = rest_filters.NumberFilter(label='responsible', method='filter_responsible') issued_by = rest_filters.ModelChoiceFilter(
queryset=Owner.objects.all(),
label=_('Issued By'),
method='filter_issued_by'
)
def filter_responsible(self, queryset, name, value): def filter_issued_by(self, queryset, name, owner):
"""Filter by 'owner' which issued the order."""
if owner.label() == 'user':
user = User.objects.get(pk=owner.owner_id)
return queryset.filter(issued_by=user)
elif owner.label() == 'group':
group = User.objects.filter(groups__pk=owner.owner_id)
return queryset.filter(issued_by__in=group)
else:
return queryset.none()
assigned_to = rest_filters.ModelChoiceFilter(
queryset=Owner.objects.all(),
field_name='responsible',
label=_('Assigned To')
)
def filter_responsible(self, queryset, name, owner):
"""Filter by orders which are assigned to the specified owner.""" """Filter by orders which are assigned to the specified owner."""
owners = list(Owner.objects.filter(pk=value)) owners = list(Owner.objects.filter(pk=value))
# if we query by a user, also find all ownerships through group memberships # if we query by a user, also find all ownerships through group memberships

View File

@ -77,7 +77,7 @@ class OrderFilter(rest_filters.FilterSet):
"""Base class for custom API filters for the OrderList endpoint.""" """Base class for custom API filters for the OrderList endpoint."""
# Filter against order status # Filter against order status
status = rest_filters.NumberFilter(label='Order Status', method='filter_status') status = rest_filters.NumberFilter(label=_('Order Status'), method='filter_status')
def filter_status(self, queryset, name, value): def filter_status(self, queryset, name, value):
"""Filter by integer status code.""" """Filter by integer status code."""
@ -85,11 +85,11 @@ class OrderFilter(rest_filters.FilterSet):
# Exact match for reference # Exact match for reference
reference = rest_filters.CharFilter( reference = rest_filters.CharFilter(
label='Filter by exact reference', field_name='reference', lookup_expr='iexact' label=_('Order Reference'), field_name='reference', lookup_expr='iexact'
) )
assigned_to_me = rest_filters.BooleanFilter( assigned_to_me = rest_filters.BooleanFilter(
label='assigned_to_me', method='filter_assigned_to_me' label=_('Assigned to me'), method='filter_assigned_to_me'
) )
def filter_assigned_to_me(self, queryset, name, value): def filter_assigned_to_me(self, queryset, name, value):
@ -113,7 +113,7 @@ class OrderFilter(rest_filters.FilterSet):
return queryset.exclude(self.Meta.model.overdue_filter()) return queryset.exclude(self.Meta.model.overdue_filter())
outstanding = rest_filters.BooleanFilter( outstanding = rest_filters.BooleanFilter(
label='outstanding', method='filter_outstanding' label=_('Outstanding'), method='filter_outstanding'
) )
def filter_outstanding(self, queryset, name, value): def filter_outstanding(self, queryset, name, value):
@ -123,11 +123,13 @@ class OrderFilter(rest_filters.FilterSet):
return queryset.exclude(status__in=self.Meta.model.get_status_class().OPEN) return queryset.exclude(status__in=self.Meta.model.get_status_class().OPEN)
project_code = rest_filters.ModelChoiceFilter( project_code = rest_filters.ModelChoiceFilter(
queryset=common.models.ProjectCode.objects.all(), field_name='project_code' queryset=common.models.ProjectCode.objects.all(),
field_name='project_code',
label=_('Project Code'),
) )
has_project_code = rest_filters.BooleanFilter( has_project_code = rest_filters.BooleanFilter(
label='has_project_code', method='filter_has_project_code' method='filter_has_project_code', label=_('Has Project Code')
) )
def filter_has_project_code(self, queryset, name, value): def filter_has_project_code(self, queryset, name, value):
@ -137,7 +139,7 @@ class OrderFilter(rest_filters.FilterSet):
return queryset.filter(project_code=None) return queryset.filter(project_code=None)
assigned_to = rest_filters.ModelChoiceFilter( assigned_to = rest_filters.ModelChoiceFilter(
queryset=Owner.objects.all(), field_name='responsible' queryset=Owner.objects.all(), field_name='responsible', label=_('Responsible')
) )

View File

@ -18,28 +18,27 @@
*/ */
// Construct a dynamic API filter for the "issued by" field // Construct a dynamic API filter for an "owner"
function constructIssuedByFilter() { function constructOwnerFilter(title) {
return { return {
title: '{% trans "Issued By" %}', title: title,
options: function() { options: function() {
let users = {}; var ownersList = {};
inventreeGet('{% url "api-owner-list" %}', {}, {
inventreeGet('{% url "api-user-list" %}', {}, {
async: false, async: false,
success: function(response) { success: function(response) {
for (let user of response) { for (var key in response) {
users[user.pk] = { let owner = response[key];
key: user.pk, ownersList[owner.pk] = {
value: user.username key: owner.pk,
value: `${owner.name} (${owner.label})`,
}; };
} }
} }
}); });
return ownersList;
return users; },
} };
}
} }
// Construct a dynamic API filter for the "project" field // Construct a dynamic API filter for the "project" field
@ -549,26 +548,8 @@ function getBuildTableFilters() {
type: 'bool', type: 'bool',
title: '{% trans "Assigned to me" %}', title: '{% trans "Assigned to me" %}',
}, },
assigned_to: { assigned_to: constructOwnerFilter('{% trans "Responsible" %}'),
title: '{% trans "Responsible" %}', issued_by: constructOwnerFilter('{% trans "Issued By" %}'),
options: function() {
var ownersList = {};
inventreeGet('{% url "api-owner-list" %}', {}, {
async: false,
success: function(response) {
for (var key in response) {
let owner = response[key];
ownersList[owner.pk] = {
key: owner.pk,
value: `${owner.name} (${owner.label})`,
};
}
}
});
return ownersList;
},
},
issued_by: constructIssuedByFilter(),
}; };
if (global_settings.PROJECT_CODES_ENABLED) { if (global_settings.PROJECT_CODES_ENABLED) {

View File

@ -8,11 +8,7 @@ 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 { import { useOwnerFilters, useProjectCodeFilters } from '../../hooks/UseFilter';
useOwnerFilters,
useProjectCodeFilters,
useUserFilters
} from '../../hooks/UseFilter';
import { useCreateApiFormModal } from '../../hooks/UseForm'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
@ -103,8 +99,7 @@ export function BuildOrderTable({
const tableColumns = useMemo(() => buildOrderTableColumns(), []); const tableColumns = useMemo(() => buildOrderTableColumns(), []);
const projectCodeFilters = useProjectCodeFilters(); const projectCodeFilters = useProjectCodeFilters();
const userFilters = useUserFilters(); const ownerFilters = useOwnerFilters();
const responsibleFilters = useOwnerFilters();
const tableFilters: TableFilter[] = useMemo(() => { const tableFilters: TableFilter[] = useMemo(() => {
return [ return [
@ -147,20 +142,16 @@ export function BuildOrderTable({
name: 'issued_by', name: 'issued_by',
label: t`Issued By`, label: t`Issued By`,
description: t`Filter by user who issued this order`, description: t`Filter by user who issued this order`,
choices: userFilters.choices choices: ownerFilters.choices
}, },
{ {
name: 'assigned_to', name: 'assigned_to',
label: t`Responsible`, label: t`Responsible`,
description: t`Filter by responsible owner`, description: t`Filter by responsible owner`,
choices: responsibleFilters.choices choices: ownerFilters.choices
} }
]; ];
}, [ }, [projectCodeFilters.choices, ownerFilters.choices]);
projectCodeFilters.choices,
userFilters.choices,
responsibleFilters.choices
]);
const user = useUserState(); const user = useUserState();