From 079e331bf6f0b57f2f5464ecdadd1eccd59b8138 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 9 Jul 2021 13:04:48 +1000 Subject: [PATCH] Add sub_part_assembly filter to BOM table --- InvenTree/part/api.py | 110 ++++++++++-------------- InvenTree/templates/js/bom.js | 2 +- InvenTree/templates/js/table_filters.js | 4 + 3 files changed, 49 insertions(+), 67 deletions(-) diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 60bf360f73..4ea5cc8d8c 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -8,7 +8,7 @@ from __future__ import unicode_literals from django.conf.urls import url, include from django.urls import reverse from django.http import JsonResponse -from django.db.models import Q, F, Count, Min, Max, Avg +from django.db.models import Q, F, Count, Min, Max, Avg, query from django.utils.translation import ugettext_lazy as _ from rest_framework import status @@ -489,7 +489,8 @@ class PartFilter(rest_filters.FilterSet): class PartList(generics.ListCreateAPIView): - """ API endpoint for accessing a list of Part objects + """ + API endpoint for accessing a list of Part objects - GET: Return list of objects - POST: Create a new Part object @@ -840,14 +841,54 @@ class PartParameterDetail(generics.RetrieveUpdateDestroyAPIView): serializer_class = part_serializers.PartParameterSerializer +class BomFilter(rest_filters.FilterSet): + """ + Custom filters for the BOM list + """ + + # Boolean filters for BOM item + optional = rest_filters.BooleanFilter(label='BOM line is optional') + inherited = rest_filters.BooleanFilter(label='BOM line is inherited') + allow_variants = rest_filters.BooleanFilter(label='Variants are allowed') + + validated = rest_filters.BooleanFilter(label='BOM line has been validated', method='filter_validated') + + def filter_validated(self, queryset, name, value): + + # Work out which lines have actually been validated + pks = [] + + for bom_item in queryset.all(): + if bom_item.is_line_valid(): + pks.append(bom_item.pk) + + if str2bool(value): + queryset = queryset.filter(pk__in=pks) + else: + queryset = queryset.exclude(pk__in=pks) + + return queryset + + # Filters for linked 'part' + part_active = rest_filters.BooleanFilter(label='Master part is active', field_name='part__active') + part_trackable = rest_filters.BooleanFilter(label='Master part is trackable', field_name='part__trackable') + + # Filters for linked 'sub_part' + sub_part_trackable = rest_filters.BooleanFilter(label='Sub part is trackable', field_name='sub_part__trackable') + sub_part_assembly = rest_filters.BooleanFilter(label='Sub part is an assembly', field_name='sub_part__assembly') + + class BomList(generics.ListCreateAPIView): - """ API endpoint for accessing a list of BomItem objects. + """ + API endpoint for accessing a list of BomItem objects. - GET: Return list of BomItem objects - POST: Create a new BomItem object """ serializer_class = part_serializers.BomItemSerializer + queryset = BomItem.objects.all() + filterset_class = BomFilter def list(self, request, *args, **kwargs): @@ -894,30 +935,6 @@ class BomList(generics.ListCreateAPIView): params = self.request.query_params - # Filter by "optional" status? - optional = params.get('optional', None) - - if optional is not None: - optional = str2bool(optional) - - queryset = queryset.filter(optional=optional) - - # Filter by "inherited" status - inherited = params.get('inherited', None) - - if inherited is not None: - inherited = str2bool(inherited) - - queryset = queryset.filter(inherited=inherited) - - # Filter by "allow_variants" - variants = params.get("allow_variants", None) - - if variants is not None: - variants = str2bool(variants) - - queryset = queryset.filter(allow_variants=variants) - # Filter by part? part = params.get('part', None) @@ -940,45 +957,6 @@ class BomList(generics.ListCreateAPIView): except (ValueError, Part.DoesNotExist): pass - # Filter by "active" status of the part - part_active = params.get('part_active', None) - - if part_active is not None: - part_active = str2bool(part_active) - queryset = queryset.filter(part__active=part_active) - - # Filter by "trackable" status of the part - part_trackable = params.get('part_trackable', None) - - if part_trackable is not None: - part_trackable = str2bool(part_trackable) - queryset = queryset.filter(part__trackable=part_trackable) - - # Filter by "trackable" status of the sub-part - sub_part_trackable = params.get('sub_part_trackable', None) - - if sub_part_trackable is not None: - sub_part_trackable = str2bool(sub_part_trackable) - queryset = queryset.filter(sub_part__trackable=sub_part_trackable) - - # Filter by whether the BOM line has been validated - validated = params.get('validated', None) - - if validated is not None: - validated = str2bool(validated) - - # Work out which lines have actually been validated - pks = [] - - for bom_item in queryset.all(): - if bom_item.is_line_valid: - pks.append(bom_item.pk) - - if validated: - queryset = queryset.filter(pk__in=pks) - else: - queryset = queryset.exclude(pk__in=pks) - # Annotate with purchase prices queryset = queryset.annotate( purchase_price_min=Min('sub_part__stock_items__purchase_price'), diff --git a/InvenTree/templates/js/bom.js b/InvenTree/templates/js/bom.js index 980dd82ccc..32166d972a 100644 --- a/InvenTree/templates/js/bom.js +++ b/InvenTree/templates/js/bom.js @@ -242,7 +242,7 @@ function loadBomTable(table, options) { return renderLink(text, url); } }); - + cols.push( { field: 'purchase_price_range', diff --git a/InvenTree/templates/js/table_filters.js b/InvenTree/templates/js/table_filters.js index 3dfb424edf..78632d6d56 100644 --- a/InvenTree/templates/js/table_filters.js +++ b/InvenTree/templates/js/table_filters.js @@ -42,6 +42,10 @@ function getAvailableTableFilters(tableKey) { type: 'bool', title: '{% trans "Trackable Part" %}' }, + sub_part_assembly: { + type: 'bool', + title: '{% trans "Assembled Part" %}', + }, validated: { type: 'bool', title: '{% trans "Validated" %}',