diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index 1114f982d3..cbb567a9e9 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -2,11 +2,14 @@ # InvenTree API version -INVENTREE_API_VERSION = 127 +INVENTREE_API_VERSION = 128 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v128 -> 2023-07-06 : https://github.com/inventree/InvenTree/pull/5186 + - Adds 'available' filter for BuildLine API endpoint + v127 -> 2023-06-24 : https://github.com/inventree/InvenTree/pull/5094 - Enhancements for the PartParameter API endpoints diff --git a/InvenTree/build/api.py b/InvenTree/build/api.py index 63ae432159..9031dfd3d7 100644 --- a/InvenTree/build/api.py +++ b/InvenTree/build/api.py @@ -1,6 +1,6 @@ """JSON API for the Build app.""" -from django.db.models import F +from django.db.models import F, Q from django.urls import include, path, re_path from django.utils.translation import gettext_lazy as _ from django.contrib.auth.models import User @@ -297,6 +297,25 @@ class BuildLineFilter(rest_filters.FilterSet): else: return queryset.filter(allocated__lt=F('quantity')) + available = rest_filters.BooleanFilter(label=_('Available'), method='filter_available') + + def filter_available(self, queryset, name, value): + """Filter by whether there is sufficient stock available for each BuildLine: + + To determine this, we need to know: + + - The quantity required for each BuildLine + - The quantity available for each BuildLine + - The quantity allocated for each BuildLine + """ + + flt = Q(quantity__lte=F('total_available_stock') + F('allocated')) + + if str2bool(value): + return queryset.filter(flt) + else: + return queryset.exclude(flt) + class BuildLineEndpoint: """Mixin class for BuildLine API endpoints.""" diff --git a/InvenTree/build/serializers.py b/InvenTree/build/serializers.py index ddd4a95307..a33f4bc84b 100644 --- a/InvenTree/build/serializers.py +++ b/InvenTree/build/serializers.py @@ -1063,6 +1063,7 @@ class BuildLineSerializer(InvenTreeModelSerializer): 'available_stock', 'available_substitute_stock', 'available_variant_stock', + 'total_available_stock', ] read_only_fields = [ @@ -1084,6 +1085,7 @@ class BuildLineSerializer(InvenTreeModelSerializer): available_stock = serializers.FloatField(read_only=True) available_substitute_stock = serializers.FloatField(read_only=True) available_variant_stock = serializers.FloatField(read_only=True) + total_available_stock = serializers.FloatField(read_only=True) @staticmethod def annotate_queryset(queryset): @@ -1185,6 +1187,14 @@ class BuildLineSerializer(InvenTreeModelSerializer): ) ) + # Annotate with the 'total available stock' + queryset = queryset.annotate( + total_available_stock=ExpressionWrapper( + F('available_stock') + F('available_substitute_stock') + F('available_variant_stock'), + output_field=FloatField(), + ) + ) + return queryset