2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-13 02:25:38 +00:00

Fixes for aggregation issues

- Ensure that "distinct=True" is set!
- ARRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
This commit is contained in:
Oliver Walters
2020-04-19 22:54:46 +10:00
parent 85d1c585c0
commit 69b8eed028
2 changed files with 175 additions and 82 deletions

View File

@ -10,6 +10,12 @@ from .models import PartCategory
from .models import BomItem
from .models import PartParameter, PartParameterTemplate
from decimal import Decimal
from django.db.models import Q, F, Sum, Count
from django.db.models.functions import Coalesce
from InvenTree.status_codes import StockStatus, OrderStatus, BuildStatus
from InvenTree.serializers import InvenTreeModelSerializer
@ -78,24 +84,77 @@ class PartSerializer(InvenTreeModelSerializer):
Used when displaying all details of a single component.
"""
allocated_stock = serializers.FloatField(source='allocation_count', read_only=True)
bom_items = serializers.IntegerField(source='bom_count', read_only=True)
building = serializers.FloatField(source='quantity_being_built', read_only=False)
category_name = serializers.CharField(source='category_path', read_only=True)
image = serializers.CharField(source='get_image_url', read_only=True)
on_order = serializers.FloatField(read_only=True)
thumbnail = serializers.CharField(source='get_thumbnail_url', read_only=True)
url = serializers.CharField(source='get_absolute_url', read_only=True)
used_in = serializers.IntegerField(source='used_in_count', read_only=True)
@staticmethod
def prefetch_queryset(queryset):
return queryset.prefetch_related(
'category',
'stock_items',
'bom_items',
'builds',
'supplier_parts',
'supplier_parts__purchase_order_line_items',
'supplier_parts__purcahes_order_line_items__order'
)
@staticmethod
def setup_eager_loading(queryset):
queryset = queryset.prefetch_related('category')
queryset = queryset.prefetch_related('stock_items')
queryset = queryset.prefetch_related('bom_items')
queryset = queryset.prefetch_related('builds')
def annotate_queryset(queryset):
"""
Add some extra annotations to the queryset,
performing database queries as efficiently as possible,
to reduce database trips.
"""
# Filter to limit stock items to "available"
stock_filter = Q(stock_items__status__in=StockStatus.AVAILABLE_CODES)
# Filter to limit orders to "open"
order_filter = Q(supplier_parts__purchase_order_line_items__order__status__in=OrderStatus.OPEN)
# Filter to limit builds to "active"
build_filter = Q(builds__status__in=BuildStatus.ACTIVE_CODES)
# Annotate the number total stock count
queryset = queryset.annotate(
in_stock=Coalesce(Sum('stock_items__quantity', filter=stock_filter, distinct=True), Decimal(0))
)
# Annotate the number of parts "on order"
# Total "on order" parts = "Quantity" - "Received" for each active purchase order
queryset = queryset.annotate(
ordering=Coalesce(Sum(
'supplier_parts__purchase_order_line_items__quantity',
filter=order_filter,
distinct=True
), Decimal(0)) - Coalesce(Sum(
'supplier_parts__purchase_order_line_items__received',
filter=order_filter,
distinct=True
), Decimal(0))
)
# Annotate number of parts being build
queryset = queryset.annotate(
building=Coalesce(
Sum('builds__quantity', filter=build_filter, distinct=True), Decimal(0)
)
)
return queryset
in_stock = serializers.FloatField(read_only=True)
ordering = serializers.FloatField(read_only=True)
building = serializers.FloatField(read_only=True)
#allocated_stock = serializers.FloatField(source='allocation_count', read_only=True)
#bom_items = serializers.IntegerField(source='bom_count', read_only=True)
#building = serializers.FloatField(source='quantity_being_built', read_only=False)
#category_name = serializers.CharField(source='category_path', read_only=True)
image = serializers.CharField(source='get_image_url', read_only=True)
#on_order = serializers.FloatField(read_only=True)
thumbnail = serializers.CharField(source='get_thumbnail_url', read_only=True)
url = serializers.CharField(source='get_absolute_url', read_only=True)
#used_in = serializers.IntegerField(source='used_in_count', read_only=True)
# TODO - Include a 'category_detail' field which serializers the category object
class Meta:
@ -103,31 +162,34 @@ class PartSerializer(InvenTreeModelSerializer):
partial = True
fields = [
'active',
'allocated_stock',
#'allocated_stock',
'assembly',
'bom_items',
'building',
#'bom_items',
#'building',
'category',
'category_name',
#'category_name',
'component',
'description',
'full_name',
'image',
'in_stock',
'ordering',
'building',
'IPN',
'is_template',
'keywords',
'link',
'name',
'notes',
'on_order',
#'on_order',
'pk',
'purchaseable',
'salable',
'thumbnail',
'trackable',
'total_stock',
#'total_stock',
'units',
'used_in',
#'used_in',
'url', # Link to the part detail page
'variant_of',
'virtual',