From ae4ebab957be7ff74ce248a0606eb16e11ef4c0c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 17 Feb 2020 22:37:55 +1100 Subject: [PATCH] Display table of StockItems which have been split from the current item - The StockItem list api now allows filtering by 'ancestor' - Add 'children' tab for StockItem - Needed to tweak the unit testing fixtures (yay thanks MPTT) --- InvenTree/stock/api.py | 21 ++++++++-- InvenTree/stock/fixtures/stock.yaml | 26 +++++++++++- InvenTree/stock/models.py | 7 +++- .../stock/templates/stock/item_base.html | 2 +- .../stock/templates/stock/item_childs.html | 42 +++++++++++++++++++ InvenTree/stock/templates/stock/tabs.html | 3 ++ InvenTree/stock/urls.py | 1 + 7 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 InvenTree/stock/templates/stock/item_childs.html diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index af2d724f58..8cd349c213 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -257,6 +257,7 @@ class StockList(generics.ListCreateAPIView): - location: Filter stock by location - category: Filter by parts belonging to a certain category - supplier: Filter by supplier + - ancestor: Filter by an 'ancestor' StockItem """ def get_serializer(self, *args, **kwargs): @@ -284,6 +285,7 @@ class StockList(generics.ListCreateAPIView): data = queryset.values( 'pk', + 'parent', 'quantity', 'serial', 'batch', @@ -347,7 +349,20 @@ class StockList(generics.ListCreateAPIView): else: stock_list = stock_list.filter(part=part_id) - except Part.DoesNotExist: + except (ValueError, Part.DoesNotExist): + pass + + # Does the client wish to filter by the 'ancestor'? + anc_id = self.request.query_params.get('ancestor', None) + + if anc_id: + try: + ancestor = StockItem.objects.get(pk=anc_id) + + # Only allow items which are descendants of the specified StockItem + stock_list = stock_list.filter(id__in=[item.pk for item in ancestor.children.all()]) + + except (ValueError, Part.DoesNotExist): pass # Does the client wish to filter by stock location? @@ -358,7 +373,7 @@ class StockList(generics.ListCreateAPIView): location = StockLocation.objects.get(pk=loc_id) stock_list = stock_list.filter(location__in=location.getUniqueChildren()) - except StockLocation.DoesNotExist: + except (ValueError, StockLocation.DoesNotExist): pass # Does the client wish to filter by part category? @@ -369,7 +384,7 @@ class StockList(generics.ListCreateAPIView): category = PartCategory.objects.get(pk=cat_id) stock_list = stock_list.filter(part__category__in=category.getUniqueChildren()) - except PartCategory.DoesNotExist: + except (ValueError, PartCategory.DoesNotExist): pass # Filter by supplier_part ID diff --git a/InvenTree/stock/fixtures/stock.yaml b/InvenTree/stock/fixtures/stock.yaml index 96e0a3ab72..ebc207f29c 100644 --- a/InvenTree/stock/fixtures/stock.yaml +++ b/InvenTree/stock/fixtures/stock.yaml @@ -7,6 +7,10 @@ location: 3 batch: 'B123' quantity: 4000 + level: 0 + tree_id: 0 + lft: 0 + rght: 0 # 5,000 screws in the bathroom - model: stock.stockitem @@ -14,6 +18,10 @@ part: 1 location: 2 quantity: 5000 + level: 0 + tree_id: 0 + lft: 0 + rght: 0 # 1234 2K2 resistors in 'Drawer_1' - model: stock.stockitem @@ -22,6 +30,10 @@ part: 3 location: 5 quantity: 1234 + level: 0 + tree_id: 0 + lft: 0 + rght: 0 # Some widgets in drawer 3 - model: stock.stockitem @@ -31,6 +43,10 @@ location: 7 quantity: 10 delete_on_deplete: False + level: 0 + tree_id: 0 + lft: 0 + rght: 0 - model: stock.stockitem pk: 101 @@ -38,10 +54,18 @@ part: 25 location: 7 quantity: 5 + level: 0 + tree_id: 0 + lft: 0 + rght: 0 - model: stock.stockitem pk: 102 fields: part: 25 location: 7 - quantity: 3 \ No newline at end of file + quantity: 3 + level: 0 + tree_id: 0 + lft: 0 + rght: 0 \ No newline at end of file diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index dcea62a4bb..1e11525703 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -385,12 +385,17 @@ class StockItem(MPTTModel): return True + @property + def children(self): + """ Return a list of the child items which have been split from this stock item """ + return self.get_descendants(include_self=False) + @property def child_count(self): """ Return the number of 'child' items associated with this StockItem. A child item is one which has been split from this one. """ - return self.get_descendants(include_self=False).count() + return self.children.count() @property def in_stock(self): diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index 3783f6a43f..4e32356101 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -59,7 +59,7 @@ {% endif %} {% if item.parent %}
- {% trans "This stock item has been split from " %}{{ item.parent }} + {% trans "This stock item was split from " %}{{ item.parent }}
{% endif %} diff --git a/InvenTree/stock/templates/stock/item_childs.html b/InvenTree/stock/templates/stock/item_childs.html new file mode 100644 index 0000000000..1a8febbbea --- /dev/null +++ b/InvenTree/stock/templates/stock/item_childs.html @@ -0,0 +1,42 @@ +{% extends "stock/item_base.html" %} + +{% load static %} +{% load i18n %} + +{% block details %} + +{% include "stock/tabs.html" with tab='children' %} + +
+ +

{% trans "Child Stock Items" %}

+ +{% if item.child_count > 0 %} +{% include "stock_table.html" %} +{% else %} +
+ {% trans "This stock item does not have any child items" %} +
+{% endif %} + +{% endblock %} + +{% block js_ready %} +{{ block.super }} + +{% if item.child_count > 0 %} +loadStockTable($("#stock-table"), { + params: { + location_detail: true, + part_details: true, + ancestor: {{ item.id }}, + }, + groupByField: 'location', + buttons: [ + '#stock-options', + ], + url: "{% url 'api-stock-list' %}", +}); +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/tabs.html b/InvenTree/stock/templates/stock/tabs.html index ac381a76ab..378f74e28e 100644 --- a/InvenTree/stock/templates/stock/tabs.html +++ b/InvenTree/stock/templates/stock/tabs.html @@ -4,6 +4,9 @@ {% trans "Tracking" %} + + {% trans "Children" %}{% if item.child_count > 0 %}{{ item.child_count }}{% endif %} + {% if 0 %} diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index 50ac170ce3..f69dc8b63f 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -24,6 +24,7 @@ stock_item_detail_urls = [ url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'), + url(r'^children/', views.StockItemDetail.as_view(template_name='stock/item_childs.html'), name='stock-item-children'), url(r'^notes/', views.StockItemNotes.as_view(), name='stock-item-notes'), url('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'),