mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 13:15:43 +00:00 
			
		
		
		
	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)
This commit is contained in:
		| @@ -257,6 +257,7 @@ class StockList(generics.ListCreateAPIView): | |||||||
|         - location: Filter stock by location |         - location: Filter stock by location | ||||||
|         - category: Filter by parts belonging to a certain category |         - category: Filter by parts belonging to a certain category | ||||||
|         - supplier: Filter by supplier |         - supplier: Filter by supplier | ||||||
|  |         - ancestor: Filter by an 'ancestor' StockItem | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def get_serializer(self, *args, **kwargs): |     def get_serializer(self, *args, **kwargs): | ||||||
| @@ -284,6 +285,7 @@ class StockList(generics.ListCreateAPIView): | |||||||
|  |  | ||||||
|         data = queryset.values( |         data = queryset.values( | ||||||
|             'pk', |             'pk', | ||||||
|  |             'parent', | ||||||
|             'quantity', |             'quantity', | ||||||
|             'serial', |             'serial', | ||||||
|             'batch', |             'batch', | ||||||
| @@ -347,7 +349,20 @@ class StockList(generics.ListCreateAPIView): | |||||||
|                 else: |                 else: | ||||||
|                     stock_list = stock_list.filter(part=part_id) |                     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 |                 pass | ||||||
|  |  | ||||||
|         # Does the client wish to filter by stock location? |         # Does the client wish to filter by stock location? | ||||||
| @@ -358,7 +373,7 @@ class StockList(generics.ListCreateAPIView): | |||||||
|                 location = StockLocation.objects.get(pk=loc_id) |                 location = StockLocation.objects.get(pk=loc_id) | ||||||
|                 stock_list = stock_list.filter(location__in=location.getUniqueChildren()) |                 stock_list = stock_list.filter(location__in=location.getUniqueChildren()) | ||||||
|                   |                   | ||||||
|             except StockLocation.DoesNotExist: |             except (ValueError, StockLocation.DoesNotExist): | ||||||
|                 pass |                 pass | ||||||
|  |  | ||||||
|         # Does the client wish to filter by part category? |         # Does the client wish to filter by part category? | ||||||
| @@ -369,7 +384,7 @@ class StockList(generics.ListCreateAPIView): | |||||||
|                 category = PartCategory.objects.get(pk=cat_id) |                 category = PartCategory.objects.get(pk=cat_id) | ||||||
|                 stock_list = stock_list.filter(part__category__in=category.getUniqueChildren()) |                 stock_list = stock_list.filter(part__category__in=category.getUniqueChildren()) | ||||||
|  |  | ||||||
|             except PartCategory.DoesNotExist: |             except (ValueError, PartCategory.DoesNotExist): | ||||||
|                 pass |                 pass | ||||||
|  |  | ||||||
|         # Filter by supplier_part ID |         # Filter by supplier_part ID | ||||||
|   | |||||||
| @@ -7,6 +7,10 @@ | |||||||
|     location: 3 |     location: 3 | ||||||
|     batch: 'B123' |     batch: 'B123' | ||||||
|     quantity: 4000 |     quantity: 4000 | ||||||
|  |     level: 0 | ||||||
|  |     tree_id: 0 | ||||||
|  |     lft: 0 | ||||||
|  |     rght: 0 | ||||||
|  |  | ||||||
| # 5,000 screws in the bathroom | # 5,000 screws in the bathroom | ||||||
| - model: stock.stockitem | - model: stock.stockitem | ||||||
| @@ -14,6 +18,10 @@ | |||||||
|     part: 1 |     part: 1 | ||||||
|     location: 2 |     location: 2 | ||||||
|     quantity: 5000 |     quantity: 5000 | ||||||
|  |     level: 0 | ||||||
|  |     tree_id: 0 | ||||||
|  |     lft: 0 | ||||||
|  |     rght: 0 | ||||||
|  |  | ||||||
| # 1234 2K2 resistors in 'Drawer_1' | # 1234 2K2 resistors in 'Drawer_1' | ||||||
| - model: stock.stockitem | - model: stock.stockitem | ||||||
| @@ -22,6 +30,10 @@ | |||||||
|     part: 3 |     part: 3 | ||||||
|     location: 5 |     location: 5 | ||||||
|     quantity: 1234 |     quantity: 1234 | ||||||
|  |     level: 0 | ||||||
|  |     tree_id: 0 | ||||||
|  |     lft: 0 | ||||||
|  |     rght: 0 | ||||||
|  |  | ||||||
| # Some widgets in drawer 3 | # Some widgets in drawer 3 | ||||||
| - model: stock.stockitem | - model: stock.stockitem | ||||||
| @@ -31,6 +43,10 @@ | |||||||
|     location: 7 |     location: 7 | ||||||
|     quantity: 10 |     quantity: 10 | ||||||
|     delete_on_deplete: False |     delete_on_deplete: False | ||||||
|  |     level: 0 | ||||||
|  |     tree_id: 0 | ||||||
|  |     lft: 0 | ||||||
|  |     rght: 0 | ||||||
|  |  | ||||||
| - model: stock.stockitem | - model: stock.stockitem | ||||||
|   pk: 101 |   pk: 101 | ||||||
| @@ -38,10 +54,18 @@ | |||||||
|     part: 25 |     part: 25 | ||||||
|     location: 7 |     location: 7 | ||||||
|     quantity: 5 |     quantity: 5 | ||||||
|  |     level: 0 | ||||||
|  |     tree_id: 0 | ||||||
|  |     lft: 0 | ||||||
|  |     rght: 0 | ||||||
|  |  | ||||||
| - model: stock.stockitem | - model: stock.stockitem | ||||||
|   pk: 102 |   pk: 102 | ||||||
|   fields: |   fields: | ||||||
|     part: 25 |     part: 25 | ||||||
|     location: 7 |     location: 7 | ||||||
|     quantity: 3 |     quantity: 3 | ||||||
|  |     level: 0 | ||||||
|  |     tree_id: 0 | ||||||
|  |     lft: 0 | ||||||
|  |     rght: 0 | ||||||
| @@ -385,12 +385,17 @@ class StockItem(MPTTModel): | |||||||
|  |  | ||||||
|         return True |         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 |     @property | ||||||
|     def child_count(self): |     def child_count(self): | ||||||
|         """ Return the number of 'child' items associated with this StockItem. |         """ Return the number of 'child' items associated with this StockItem. | ||||||
|         A child item is one which has been split from this one. |         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 |     @property | ||||||
|     def in_stock(self): |     def in_stock(self): | ||||||
|   | |||||||
| @@ -59,7 +59,7 @@ | |||||||
|         {% endif %} |         {% endif %} | ||||||
|         {% if item.parent %} |         {% if item.parent %} | ||||||
|         <div class='alert alert-block alert-info'> |         <div class='alert alert-block alert-info'> | ||||||
|             {% trans "This stock item has been split from " %}<a href="{% url 'stock-item-detail' item.parent.id %}">{{ item.parent }}</a> |             {% trans "This stock item was split from " %}<a href="{% url 'stock-item-detail' item.parent.id %}">{{ item.parent }}</a> | ||||||
|         </div> |         </div> | ||||||
|         {% endif %} |         {% endif %} | ||||||
|         </div> |         </div> | ||||||
|   | |||||||
							
								
								
									
										42
									
								
								InvenTree/stock/templates/stock/item_childs.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								InvenTree/stock/templates/stock/item_childs.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | {% extends "stock/item_base.html" %} | ||||||
|  |  | ||||||
|  | {% load static %} | ||||||
|  | {% load i18n %} | ||||||
|  |  | ||||||
|  | {% block details %} | ||||||
|  |  | ||||||
|  | {% include "stock/tabs.html" with tab='children' %} | ||||||
|  |  | ||||||
|  | <hr> | ||||||
|  |  | ||||||
|  | <h4>{% trans "Child Stock Items" %}</h4> | ||||||
|  |  | ||||||
|  | {% if item.child_count > 0 %} | ||||||
|  | {% include "stock_table.html" %} | ||||||
|  | {% else %} | ||||||
|  | <div class='alert alert-block alert-info'> | ||||||
|  |     {% trans "This stock item does not have any child items" %} | ||||||
|  | </div> | ||||||
|  | {% 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 %} | ||||||
| @@ -4,6 +4,9 @@ | |||||||
|     <li{% ifequal tab 'tracking' %} class='active'{% endifequal %}> |     <li{% ifequal tab 'tracking' %} class='active'{% endifequal %}> | ||||||
|         <a href="{% url 'stock-item-detail' item.id %}">{% trans "Tracking" %}</a> |         <a href="{% url 'stock-item-detail' item.id %}">{% trans "Tracking" %}</a> | ||||||
|     </li> |     </li> | ||||||
|  |     <li{% ifequal tab 'children' %} class='active'{% endifequal %}> | ||||||
|  |         <a href="{% url 'stock-item-children' item.id %}">{% trans "Children" %}{% if item.child_count > 0 %}<span class='badge'>{{ item.child_count }}</span>{% endif %}</a> | ||||||
|  |     </li> | ||||||
|     {% if 0 %} |     {% if 0 %} | ||||||
|     <!-- These tabs are to be implemented in the future --> |     <!-- These tabs are to be implemented in the future --> | ||||||
|     <li{% ifequal tab 'builds' %} class='active'{% endifequal %}> |     <li{% ifequal tab 'builds' %} class='active'{% endifequal %}> | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ stock_item_detail_urls = [ | |||||||
|  |  | ||||||
|     url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'), |     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(r'^notes/', views.StockItemNotes.as_view(), name='stock-item-notes'), | ||||||
|  |  | ||||||
|     url('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'), |     url('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'), | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user