diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index c5e937b10b..0d3fd7bf69 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -2,11 +2,14 @@ # InvenTree API version -INVENTREE_API_VERSION = 64 +INVENTREE_API_VERSION = 65 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v65 -> 2022-07-15 : https://github.com/inventree/InvenTree/pull/3335 + - Annotates 'in_stock' quantity to the SupplierPart API + v64 -> 2022-07-08 : https://github.com/inventree/InvenTree/pull/3310 - Annotate 'on_order' quantity to BOM list API - Allow BOM List API endpoint to be filtered by "on_order" parameter diff --git a/InvenTree/company/api.py b/InvenTree/company/api.py index 2f1e1ba421..734dd08b5e 100644 --- a/InvenTree/company/api.py +++ b/InvenTree/company/api.py @@ -263,6 +263,13 @@ class SupplierPartList(ListCreateDestroyAPIView): queryset = SupplierPart.objects.all() + def get_queryset(self, *args, **kwargs): + """Return annotated queryest object for the SupplierPart list""" + queryset = super().get_queryset(*args, **kwargs) + queryset = SupplierPartSerializer.annotate_queryset(queryset) + + return queryset + def filter_queryset(self, queryset): """Custom filtering for the queryset.""" queryset = super().filter_queryset(queryset) diff --git a/InvenTree/company/serializers.py b/InvenTree/company/serializers.py index 08947605ab..7da90f47a5 100644 --- a/InvenTree/company/serializers.py +++ b/InvenTree/company/serializers.py @@ -5,6 +5,7 @@ from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from sql_util.utils import SubqueryCount +import part.filters from common.settings import currency_code_default, currency_code_mappings from InvenTree.serializers import (InvenTreeAttachmentSerializer, InvenTreeDecimalField, @@ -199,6 +200,9 @@ class ManufacturerPartParameterSerializer(InvenTreeModelSerializer): class SupplierPartSerializer(InvenTreeModelSerializer): """Serializer for SupplierPart object.""" + # Annotated field showing total in-stock quantity + in_stock = serializers.FloatField(read_only=True) + part_detail = PartBriefSerializer(source='part', many=False, read_only=True) supplier_detail = CompanyBriefSerializer(source='supplier', many=False, read_only=True) @@ -249,6 +253,7 @@ class SupplierPartSerializer(InvenTreeModelSerializer): 'available', 'availability_updated', 'description', + 'in_stock', 'link', 'manufacturer', 'manufacturer_detail', @@ -270,6 +275,20 @@ class SupplierPartSerializer(InvenTreeModelSerializer): 'availability_updated', ] + @staticmethod + def annotate_queryset(queryset): + """Annotate the SupplierPart queryset with extra fields: + + Fields: + in_stock: Current stock quantity for each SupplierPart + """ + + queryset = queryset.annotate( + in_stock=part.filters.annotate_total_stock(reference='part__') + ) + + return queryset + def update(self, supplier_part, data): """Custom update functionality for the serializer""" diff --git a/InvenTree/templates/js/translated/company.js b/InvenTree/templates/js/translated/company.js index 8a167f5c20..5af324d32f 100644 --- a/InvenTree/templates/js/translated/company.js +++ b/InvenTree/templates/js/translated/company.js @@ -840,6 +840,7 @@ function loadSupplierPartTable(table, url, options) { queryParams: filters, name: 'supplierparts', groupBy: false, + sortable: true, formatNoMatches: function() { return '{% trans "No supplier parts found" %}'; }, @@ -957,6 +958,11 @@ function loadSupplierPartTable(table, url, options) { title: '{% trans "Packaging" %}', sortable: false, }, + { + field: 'in_stock', + title: '{% trans "In Stock" %}', + sortable: true, + }, { field: 'available', title: '{% trans "Available" %}',