From 4ee0004c97e8fdeb05d19ca891376fb5b9fae216 Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Wed, 21 Jul 2021 21:34:16 +1000
Subject: [PATCH] Filtering for Build and StockItem

---
 InvenTree/build/api.py    | 15 +++++++++++++++
 InvenTree/build/models.py |  8 ++++++++
 InvenTree/stock/api.py    | 14 ++++++++++++++
 InvenTree/stock/models.py | 11 +++++++++++
 4 files changed, 48 insertions(+)

diff --git a/InvenTree/build/api.py b/InvenTree/build/api.py
index 47edb55545..eb6d42cc6d 100644
--- a/InvenTree/build/api.py
+++ b/InvenTree/build/api.py
@@ -104,6 +104,21 @@ class BuildList(generics.ListCreateAPIView):
 
         params = self.request.query_params
 
+        # exclude parent tree
+        exclude_tree = params.get('exclude_tree', None)
+
+        if exclude_tree is not None:
+
+            try:
+                build = Build.objects.get(pk=exclude_tree)
+
+                queryset = queryset.exclude(
+                    pk__in=[bld.pk for bld in build.get_descendants(include_self=True)]
+                )
+
+            except (ValueError, Build.DoesNotExist):
+                pass
+
         # Filter by "parent"
         parent = params.get('parent', None)
 
diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py
index 5f8af9096b..084f9ab2db 100644
--- a/InvenTree/build/models.py
+++ b/InvenTree/build/models.py
@@ -96,6 +96,14 @@ class Build(MPTTModel):
     def get_api_url():
         return reverse('api-build-list')
 
+    def api_instance_filters(self):
+
+        return {
+            'parent': {
+                'exclude_tree': self.pk,
+            }
+        }
+
     def save(self, *args, **kwargs):
 
         try:
diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py
index b11f556e34..cf58c7d4d9 100644
--- a/InvenTree/stock/api.py
+++ b/InvenTree/stock/api.py
@@ -733,6 +733,20 @@ class StockList(generics.ListCreateAPIView):
         if customer:
             queryset = queryset.filter(customer=customer)
 
+        # Exclude stock item tree
+        exclude_tree = params.get('exclude_tree', None)
+
+        if exclude_tree is not None:
+            try:
+                item = StockItem.objects.get(pk=exclude_tree)
+
+                queryset = queryset.exclude(
+                    pk__in=[it.pk for it in item.get_descendants(include_self=True)]
+                )
+
+            except (ValueError, StockItem.DoesNotExist):
+                pass
+
         # Filter by 'allocated' parts?
         allocated = params.get('allocated', None)
 
diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py
index c2122f40ac..11d5de9bf1 100644
--- a/InvenTree/stock/models.py
+++ b/InvenTree/stock/models.py
@@ -191,6 +191,17 @@ class StockItem(MPTTModel):
     def get_api_url():
         return reverse('api-stock-list')
 
+    def api_instance_filters(self):
+        """
+        Custom API instance filters
+        """
+
+        return {
+            'parent': {
+                'exclude_tree': self.pk,
+            }
+        }
+
     # A Query filter which will be re-used in multiple places to determine if a StockItem is actually "in stock"
     IN_STOCK_FILTER = Q(
         quantity__gt=0,