mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-04 07:05:41 +00:00 
			
		
		
		
	Add 'available_variant_stock' to BomItem serializer
- Note: This is definitely *not* the optimum solution here
This commit is contained in:
		@@ -2703,6 +2703,61 @@ class BomItem(models.Model, DataImportMixin):
 | 
				
			|||||||
    def get_api_url():
 | 
					    def get_api_url():
 | 
				
			||||||
        return reverse('api-bom-list')
 | 
					        return reverse('api-bom-list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def available_variant_stock(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Returns the total quantity of variant stock available for this BomItem.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Notes:
 | 
				
			||||||
 | 
					        - If "allow_variants" is False, this will return zero
 | 
				
			||||||
 | 
					        - This is used for the API serializer, and is very inefficient
 | 
				
			||||||
 | 
					        - This logic needs to be converted to a queryset annotation
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Variant stock is not allowed for this BOM item
 | 
				
			||||||
 | 
					        if not self.allow_variants:
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # Extract a flattened list of part variants
 | 
				
			||||||
 | 
					        variants = self.sub_part.get_descendants(include_self=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Calculate 'in_stock' quantity - this is the total current stock count
 | 
				
			||||||
 | 
					        query = StockModels.StockItem.objects.filter(StockModels.StockItem.IN_STOCK_FILTER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        query = query.filter(
 | 
				
			||||||
 | 
					            part__in=variants,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        query = query.aggregate(
 | 
				
			||||||
 | 
					            in_stock=Coalesce(Sum('quantity'), Decimal(0))
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        in_stock = query['in_stock'] or 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Calculate the quantity allocated to sales orders
 | 
				
			||||||
 | 
					        query = OrderModels.SalesOrderAllocation.objects.filter(
 | 
				
			||||||
 | 
					            line__order__status__in=SalesOrderStatus.OPEN,
 | 
				
			||||||
 | 
					            shipment__shipment_date=None,
 | 
				
			||||||
 | 
					            item__part__in=variants,
 | 
				
			||||||
 | 
					        ).aggregate(
 | 
				
			||||||
 | 
					            allocated=Coalesce(Sum('quantity'), Decimal(0)),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sales_order_allocations = query['allocated'] or 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Calculate the quantity allocated to build orders
 | 
				
			||||||
 | 
					        query = BuildModels.BuildItem.objects.filter(
 | 
				
			||||||
 | 
					            build__status__in=BuildStatus.ACTIVE_CODES,
 | 
				
			||||||
 | 
					            stock_item__part__in=variants,
 | 
				
			||||||
 | 
					        ).aggregate(
 | 
				
			||||||
 | 
					            allocated=Coalesce(Sum('quantity'), Decimal(0)),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        build_order_allocations = query['allocated'] or 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        available = in_stock - sales_order_allocations - build_order_allocations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return max(available, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_valid_parts_for_allocation(self, allow_variants=True, allow_substitutes=True):
 | 
					    def get_valid_parts_for_allocation(self, allow_variants=True, allow_substitutes=True):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return a list of valid parts which can be allocated against this BomItem:
 | 
					        Return a list of valid parts which can be allocated against this BomItem:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -581,6 +581,12 @@ class BomItemSerializer(InvenTreeModelSerializer):
 | 
				
			|||||||
    available_stock = serializers.FloatField(read_only=True)
 | 
					    available_stock = serializers.FloatField(read_only=True)
 | 
				
			||||||
    available_substitute_stock = serializers.FloatField(read_only=True)
 | 
					    available_substitute_stock = serializers.FloatField(read_only=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Note: 2022-04-15
 | 
				
			||||||
 | 
					    # The 'available_variant_stock' field is calculated per-object,
 | 
				
			||||||
 | 
					    # which means it is very inefficient!
 | 
				
			||||||
 | 
					    # TODO: This needs to be converted into a query annotation, if possible!
 | 
				
			||||||
 | 
					    available_variant_stock = serializers.FloatField(read_only=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, *args, **kwargs):
 | 
					    def __init__(self, *args, **kwargs):
 | 
				
			||||||
        # part_detail and sub_part_detail serializers are only included if requested.
 | 
					        # part_detail and sub_part_detail serializers are only included if requested.
 | 
				
			||||||
        # This saves a bunch of database requests
 | 
					        # This saves a bunch of database requests
 | 
				
			||||||
@@ -790,6 +796,7 @@ class BomItemSerializer(InvenTreeModelSerializer):
 | 
				
			|||||||
            # Annotated fields describing available quantity
 | 
					            # Annotated fields describing available quantity
 | 
				
			||||||
            'available_stock',
 | 
					            'available_stock',
 | 
				
			||||||
            'available_substitute_stock',
 | 
					            'available_substitute_stock',
 | 
				
			||||||
 | 
					            'available_variant_stock',
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user