mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-04 07:05:41 +00:00 
			
		
		
		
	[PUI] Child item table (#6334)
* Add child stock item table * Fix stock item splitting bug - StockItem tree was not being rebuilt correctly - Add unit tests * Annotate StockItem serializer with "child_items" count * Show or hide "child items" panel * Account for case where tree_id is zero
This commit is contained in:
		@@ -655,6 +655,16 @@ class StockFilter(rest_filters.FilterSet):
 | 
			
		||||
            return queryset.filter(installed_items__gt=0)
 | 
			
		||||
        return queryset.filter(installed_items=0)
 | 
			
		||||
 | 
			
		||||
    has_child_items = rest_filters.BooleanFilter(
 | 
			
		||||
        label='Has child items', method='filter_has_child_items'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def filter_has_child_items(self, queryset, name, value):
 | 
			
		||||
        """Filter stock items by "belongs_to" field being empty."""
 | 
			
		||||
        if str2bool(value):
 | 
			
		||||
            return queryset.filter(child_items__gt=0)
 | 
			
		||||
        return queryset.filter(child_items=0)
 | 
			
		||||
 | 
			
		||||
    sent_to_customer = rest_filters.BooleanFilter(
 | 
			
		||||
        label='Sent to customer', method='filter_sent_to_customer'
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,8 @@
 | 
			
		||||
from django.db.models import F, Func, IntegerField, OuterRef, Q, Subquery
 | 
			
		||||
from django.db.models.functions import Coalesce
 | 
			
		||||
 | 
			
		||||
from sql_util.utils import SubqueryCount
 | 
			
		||||
 | 
			
		||||
import stock.models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -33,3 +35,23 @@ def annotate_location_items(filter: Q = None):
 | 
			
		||||
        0,
 | 
			
		||||
        output_field=IntegerField(),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def annotate_child_items():
 | 
			
		||||
    """Construct a queryset annotation which returns the number of children below a certain StockItem node in a StockItem tree."""
 | 
			
		||||
    child_stock_query = stock.models.StockItem.objects.filter(
 | 
			
		||||
        tree_id=OuterRef('tree_id'),
 | 
			
		||||
        lft__gt=OuterRef('lft'),
 | 
			
		||||
        rght__lt=OuterRef('rght'),
 | 
			
		||||
        level__gte=OuterRef('level'),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    return Coalesce(
 | 
			
		||||
        Subquery(
 | 
			
		||||
            child_stock_query.annotate(
 | 
			
		||||
                count=Func(F('pk'), function='COUNT', output_field=IntegerField())
 | 
			
		||||
            ).values('count')
 | 
			
		||||
        ),
 | 
			
		||||
        0,
 | 
			
		||||
        output_field=IntegerField(),
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -170,6 +170,7 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeTagModelSerializer):
 | 
			
		||||
            'allocated',
 | 
			
		||||
            'expired',
 | 
			
		||||
            'installed_items',
 | 
			
		||||
            'child_items',
 | 
			
		||||
            'stale',
 | 
			
		||||
            'tracking_items',
 | 
			
		||||
            'tags',
 | 
			
		||||
@@ -288,6 +289,9 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeTagModelSerializer):
 | 
			
		||||
        # Annotate with the total number of "installed items"
 | 
			
		||||
        queryset = queryset.annotate(installed_items=SubqueryCount('installed_parts'))
 | 
			
		||||
 | 
			
		||||
        # Annotate with the total number of "child items" (split stock items)
 | 
			
		||||
        queryset = queryset.annotate(child_items=stock.filters.annotate_child_items())
 | 
			
		||||
 | 
			
		||||
        return queryset
 | 
			
		||||
 | 
			
		||||
    status_text = serializers.CharField(source='get_status_display', read_only=True)
 | 
			
		||||
@@ -315,6 +319,7 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeTagModelSerializer):
 | 
			
		||||
    allocated = serializers.FloatField(required=False)
 | 
			
		||||
    expired = serializers.BooleanField(required=False, read_only=True)
 | 
			
		||||
    installed_items = serializers.IntegerField(read_only=True, required=False)
 | 
			
		||||
    child_items = serializers.IntegerField(read_only=True, required=False)
 | 
			
		||||
    stale = serializers.BooleanField(required=False, read_only=True)
 | 
			
		||||
    tracking_items = serializers.IntegerField(read_only=True, required=False)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user