[PUI] Sub builds table (#7932)

* Allow table filters to be marked "inactive"

* Allow build orders to be filtering by 'cascading' parent

* Update build order table

* Bump API version
This commit is contained in:
Oliver 2024-08-20 11:21:38 +10:00 committed by GitHub
parent 6591286e27
commit 7cbaeb159e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 117 additions and 68 deletions

View File

@ -1,14 +1,19 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 241 INVENTREE_API_VERSION = 242
"""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 = """
v241 - 2024-09-18 : https://github.com/inventree/InvenTree/pull/7906 v242 - 2024-08-20 : https://github.com/inventree/InvenTree/pull/7932
- Adds "level" attribute to BuildOrder serializer
- Allow ordering of BuildOrder API by "level" attribute
- Allow "parent" filter for BuildOrder API to have "cascade=True" option
v241 - 2024-08-18 : https://github.com/inventree/InvenTree/pull/7906
- Adjusts required fields for the MeUserDetail endpoint - Adjusts required fields for the MeUserDetail endpoint
v240 - 2024-08-16 : https://github.com/inventree/InvenTree/pull/7900 v240 - 2024-08-16 : https://github.com/inventree/InvenTree/pull/7900

View File

@ -34,7 +34,6 @@ class BuildFilter(rest_filters.FilterSet):
"""Metaclass options.""" """Metaclass options."""
model = Build model = Build
fields = [ fields = [
'parent',
'sales_order', 'sales_order',
'part', 'part',
] ]
@ -49,6 +48,35 @@ class BuildFilter(rest_filters.FilterSet):
return queryset.filter(status__in=BuildStatusGroups.ACTIVE_CODES) return queryset.filter(status__in=BuildStatusGroups.ACTIVE_CODES)
return queryset.exclude(status__in=BuildStatusGroups.ACTIVE_CODES) return queryset.exclude(status__in=BuildStatusGroups.ACTIVE_CODES)
cascade = rest_filters.BooleanFilter(label=_('Cascade'), method='filter_cascade')
def filter_cascade(self, queryset, name, value):
"""Filter by whether or not the build is a 'cascade' build.
Note: this only applies when the 'parent' field filter is specified.
"""
# No filtering here, see 'filter_parent'
return queryset
parent = rest_filters.ModelChoiceFilter(
queryset=Build.objects.all(),
label=_('Parent Build'),
field_name='parent',
method='filter_parent'
)
def filter_parent(self, queryset, name, parent):
"""Filter by 'parent' build order."""
cascade = str2bool(self.data.get('cascade', False))
if cascade:
builds = parent.get_descendants(include_self=False)
return queryset.filter(pk__in=[b.pk for b in builds])
return queryset.filter(parent=parent)
overdue = rest_filters.BooleanFilter(label='Build is overdue', method='filter_overdue') overdue = rest_filters.BooleanFilter(label='Build is overdue', method='filter_overdue')
def filter_overdue(self, queryset, name, value): def filter_overdue(self, queryset, name, value):
@ -175,6 +203,7 @@ class BuildList(DataExportViewMixin, BuildMixin, ListCreateAPI):
'responsible', 'responsible',
'project_code', 'project_code',
'priority', 'priority',
'level',
] ]
ordering_field_aliases = { ordering_field_aliases = {

View File

@ -76,6 +76,7 @@ class BuildSerializer(NotesFieldMixin, DataImportExportSerializerMixin, InvenTre
'responsible', 'responsible',
'responsible_detail', 'responsible_detail',
'priority', 'priority',
'level',
] ]
read_only_fields = [ read_only_fields = [
@ -84,8 +85,11 @@ class BuildSerializer(NotesFieldMixin, DataImportExportSerializerMixin, InvenTre
'completion_data', 'completion_data',
'status', 'status',
'status_text', 'status_text',
'level',
] ]
level = serializers.IntegerField(label=_('Build Level'), read_only=True)
url = serializers.CharField(source='get_absolute_url', read_only=True) url = serializers.CharField(source='get_absolute_url', read_only=True)
status_text = serializers.CharField(source='get_status_display', read_only=True) status_text = serializers.CharField(source='get_status_display', read_only=True)

View File

@ -28,6 +28,7 @@ export type TableFilter = {
defaultValue?: any; defaultValue?: any;
value?: any; value?: any;
displayValue?: any; displayValue?: any;
active?: boolean;
}; };
/** /**

View File

@ -164,12 +164,14 @@ export function InvenTreeTable<T = any>({
// Construct table filters - note that we can introspect filter labels from column names // Construct table filters - note that we can introspect filter labels from column names
const filters: TableFilter[] = useMemo(() => { const filters: TableFilter[] = useMemo(() => {
return ( return (
props.tableFilters?.map((filter) => { props.tableFilters
return { ?.filter((f: any) => f.active != false)
...filter, ?.map((filter) => {
label: filter.label ?? fieldNames[filter.name] ?? `${filter.name}` return {
}; ...filter,
}) ?? [] label: filter.label ?? fieldNames[filter.name] ?? `${filter.name}`
};
}) ?? []
); );
}, [props.tableFilters, fieldNames]); }, [props.tableFilters, fieldNames]);

View File

@ -27,63 +27,6 @@ import {
import { StatusFilterOptions, TableFilter } from '../Filter'; import { StatusFilterOptions, TableFilter } from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
/**
* Construct a list of columns for the build order table
*/
function buildOrderTableColumns(): TableColumn[] {
return [
ReferenceColumn({}),
{
accessor: 'part',
sortable: true,
switchable: false,
render: (record: any) => PartColumn(record.part_detail)
},
{
accessor: 'part_detail.IPN',
sortable: true,
switchable: true,
title: t`IPN`
},
{
accessor: 'title',
sortable: false
},
{
accessor: 'completed',
sortable: true,
switchable: false,
render: (record: any) => (
<ProgressBar
progressLabel={true}
value={record.completed}
maximum={record.quantity}
/>
)
},
StatusColumn({ model: ModelType.build }),
ProjectCodeColumn({}),
{
accessor: 'priority',
sortable: true
},
CreationDateColumn({}),
TargetDateColumn({}),
DateColumn({
accessor: 'completion_date',
sortable: true
}),
{
accessor: 'issued_by',
sortable: true,
render: (record: any) => (
<RenderUser instance={record?.issued_by_detail} />
)
},
ResponsibleColumn({})
];
}
/* /*
* Construct a table of build orders, according to the provided parameters * Construct a table of build orders, according to the provided parameters
*/ */
@ -96,7 +39,65 @@ export function BuildOrderTable({
parentBuildId?: number; parentBuildId?: number;
salesOrderId?: number; salesOrderId?: number;
}) { }) {
const tableColumns = useMemo(() => buildOrderTableColumns(), []); const tableColumns = useMemo(() => {
return [
ReferenceColumn({}),
{
accessor: 'part',
sortable: true,
switchable: false,
render: (record: any) => PartColumn(record.part_detail)
},
{
accessor: 'part_detail.IPN',
sortable: true,
switchable: true,
title: t`IPN`
},
{
accessor: 'title',
sortable: false
},
{
accessor: 'completed',
sortable: true,
switchable: false,
render: (record: any) => (
<ProgressBar
progressLabel={true}
value={record.completed}
maximum={record.quantity}
/>
)
},
StatusColumn({ model: ModelType.build }),
ProjectCodeColumn({}),
{
accessor: 'level',
sortable: true,
switchable: true,
hidden: !parentBuildId
},
{
accessor: 'priority',
sortable: true
},
CreationDateColumn({}),
TargetDateColumn({}),
DateColumn({
accessor: 'completion_date',
sortable: true
}),
{
accessor: 'issued_by',
sortable: true,
render: (record: any) => (
<RenderUser instance={record?.issued_by_detail} />
)
},
ResponsibleColumn({})
];
}, [parentBuildId]);
const projectCodeFilters = useProjectCodeFilters(); const projectCodeFilters = useProjectCodeFilters();
const ownerFilters = useOwnerFilters(); const ownerFilters = useOwnerFilters();
@ -109,6 +110,13 @@ export function BuildOrderTable({
label: t`Active`, label: t`Active`,
description: t`Show active orders` description: t`Show active orders`
}, },
{
name: 'cascade',
type: 'boolean',
label: t`Cascade`,
description: t`Display recursive child orders`,
active: !!parentBuildId
},
{ {
name: 'status', name: 'status',
label: t`Status`, label: t`Status`,
@ -151,7 +159,7 @@ export function BuildOrderTable({
choices: ownerFilters.choices choices: ownerFilters.choices
} }
]; ];
}, [projectCodeFilters.choices, ownerFilters.choices]); }, [parentBuildId, projectCodeFilters.choices, ownerFilters.choices]);
const user = useUserState(); const user = useUserState();