diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index 8887982784..1862b082fd 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -2,11 +2,14 @@ # InvenTree API version -INVENTREE_API_VERSION = 83 +INVENTREE_API_VERSION = 84 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v84 -> 2022-12-21: https://github.com/inventree/InvenTree/pull/4083 + - Add support for listing PO, BO, SO by their reference + v83 -> 2022-11-19 : https://github.com/inventree/InvenTree/pull/3949 - Add support for structural Stock locations diff --git a/InvenTree/build/api.py b/InvenTree/build/api.py index 71b806314f..557dde30d9 100644 --- a/InvenTree/build/api.py +++ b/InvenTree/build/api.py @@ -65,6 +65,13 @@ class BuildFilter(rest_filters.FilterSet): return queryset + # Exact match for reference + reference = rest_filters.CharFilter( + label='Filter by exact reference', + field_name='reference', + lookup_expr="iexact" + ) + class BuildList(APIDownloadMixin, ListCreateAPI): """API endpoint for accessing a list of Build objects. diff --git a/InvenTree/build/test_api.py b/InvenTree/build/test_api.py index 66185b3e54..af6d7a0781 100644 --- a/InvenTree/build/test_api.py +++ b/InvenTree/build/test_api.py @@ -63,6 +63,14 @@ class TestBuildAPI(InvenTreeAPITestCase): response = self.client.get(url, {'part': 99999}, format='json') self.assertEqual(len(response.data), 0) + # Get a certain reference + response = self.client.get(url, {'reference': 'BO-0001'}, format='json') + self.assertEqual(len(response.data), 1) + + # Get a certain reference + response = self.client.get(url, {'reference': 'BO-9999XX'}, format='json') + self.assertEqual(len(response.data), 0) + def test_get_build_item_list(self): """Test that we can retrieve list of BuildItem objects.""" url = reverse('api-build-item-list') diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index 3bf9035f13..4343b021ae 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -78,8 +78,15 @@ class GeneralExtraLineList: ] -class PurchaseOrderFilter(rest_filters.FilterSet): - """Custom API filters for the PurchaseOrderList endpoint.""" +class OrderFilter(rest_filters.FilterSet): + """Base class for custom API filters for the OrderList endpoint.""" + + # Exact match for reference + reference = rest_filters.CharFilter( + label='Filter by exact reference', + field_name='reference', + lookup_expr="iexact" + ) assigned_to_me = rest_filters.BooleanFilter(label='assigned_to_me', method='filter_assigned_to_me') @@ -97,6 +104,9 @@ class PurchaseOrderFilter(rest_filters.FilterSet): return queryset + +class PurchaseOrderFilter(OrderFilter): + """Custom API filters for the PurchaseOrderList endpoint.""" class Meta: """Metaclass options.""" @@ -106,6 +116,17 @@ class PurchaseOrderFilter(rest_filters.FilterSet): ] +class SalesOrderFilter(OrderFilter): + """Custom API filters for the SalesOrderList endpoint.""" + class Meta: + """Metaclass options.""" + + model = models.SalesOrder + fields = [ + 'customer', + ] + + class PurchaseOrderList(APIDownloadMixin, ListCreateAPI): """API endpoint for accessing a list of PurchaseOrder objects. @@ -613,6 +634,7 @@ class SalesOrderList(APIDownloadMixin, ListCreateAPI): queryset = models.SalesOrder.objects.all() serializer_class = serializers.SalesOrderSerializer + filterset_class = SalesOrderFilter def create(self, request, *args, **kwargs): """Save user information on create.""" diff --git a/InvenTree/order/test_api.py b/InvenTree/order/test_api.py index dfe5732652..14f3f82df3 100644 --- a/InvenTree/order/test_api.py +++ b/InvenTree/order/test_api.py @@ -72,6 +72,14 @@ class PurchaseOrderTest(OrderTest): self.filter({'status': 10}, 3) self.filter({'status': 40}, 1) + # Filter by "reference" + self.filter({'reference': 'PO-0001'}, 1) + self.filter({'reference': 'PO-9999'}, 0) + + # Filter by "assigned_to_me" + self.filter({'assigned_to_me': 1}, 0) + self.filter({'assigned_to_me': 0}, 7) + # Filter by "part" self.filter({'part': 1}, 2) self.filter({'part': 2}, 0) # Part not assigned to any PO @@ -878,6 +886,14 @@ class SalesOrderTest(OrderTest): self.filter({'status': 20}, 1) # SHIPPED self.filter({'status': 99}, 0) # Invalid + # Filter by "reference" + self.filter({'reference': 'ABC123'}, 1) + self.filter({'reference': 'XXX999'}, 0) + + # Filter by "assigned_to_me" + self.filter({'assigned_to_me': 1}, 0) + self.filter({'assigned_to_me': 0}, 5) + def test_overdue(self): """Test "overdue" status.""" self.filter({'overdue': True}, 0)