mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-17 12:35:46 +00:00
Queryset annotation refactor (#3117)
* Refactor out 'ordering' serializer annotation field * Refactor BomItem serializer annotations * Factor out MPTT OuterRef query * Add 'available_stock' annotation to SalesOrderLineItem serializer - Allows for better rendering of stock availability in sales order table * Improve 'available quantity' rendering of salesorderlineitem table * Bump API version * Add docstring
This commit is contained in:
@ -788,6 +788,8 @@ class SalesOrderLineItemList(generics.ListCreateAPIView):
|
||||
'order__stock_items',
|
||||
)
|
||||
|
||||
queryset = serializers.SalesOrderLineItemSerializer.annotate_queryset(queryset)
|
||||
|
||||
return queryset
|
||||
|
||||
filter_backends = [
|
||||
@ -835,6 +837,14 @@ class SalesOrderLineItemDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
queryset = models.SalesOrderLineItem.objects.all()
|
||||
serializer_class = serializers.SalesOrderLineItemSerializer
|
||||
|
||||
def get_queryset(self, *args, **kwargs):
|
||||
"""Return annotated queryset for this endpoint"""
|
||||
queryset = super().get_queryset(*args, **kwargs)
|
||||
|
||||
queryset = serializers.SalesOrderLineItemSerializer.annotate_queryset(queryset)
|
||||
|
||||
return queryset
|
||||
|
||||
|
||||
class SalesOrderContextMixin:
|
||||
"""Mixin to add sales order object as serializer context variable."""
|
||||
|
@ -887,14 +887,6 @@ class OrderLineItem(models.Model):
|
||||
target_date: An (optional) date for expected shipment of this line item.
|
||||
"""
|
||||
|
||||
"""
|
||||
Query filter for determining if an individual line item is "overdue":
|
||||
- Amount received is less than the required quantity
|
||||
- Target date is not None
|
||||
- Target date is in the past
|
||||
"""
|
||||
OVERDUE_FILTER = Q(received__lt=F('quantity')) & ~Q(target_date=None) & Q(target_date__lt=datetime.now().date())
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options. Abstract ensures no database table is created."""
|
||||
|
||||
@ -953,6 +945,9 @@ class PurchaseOrderLineItem(OrderLineItem):
|
||||
order: Reference to a PurchaseOrder object
|
||||
"""
|
||||
|
||||
# Filter for determining if a particular PurchaseOrderLineItem is overdue
|
||||
OVERDUE_FILTER = Q(received__lt=F('quantity')) & ~Q(target_date=None) & Q(target_date__lt=datetime.now().date())
|
||||
|
||||
@staticmethod
|
||||
def get_api_url():
|
||||
"""Return the API URL associated with the PurchaseOrderLineItem model"""
|
||||
@ -1076,6 +1071,9 @@ class SalesOrderLineItem(OrderLineItem):
|
||||
shipped: The number of items which have actually shipped against this line item
|
||||
"""
|
||||
|
||||
# Filter for determining if a particular SalesOrderLineItem is overdue
|
||||
OVERDUE_FILTER = Q(shipped__lt=F('quantity')) & ~Q(target_date=None) & Q(target_date__lt=datetime.now().date())
|
||||
|
||||
@staticmethod
|
||||
def get_api_url():
|
||||
"""Return the API URL associated with the SalesOrderLineItem model"""
|
||||
|
@ -14,6 +14,7 @@ from rest_framework.serializers import ValidationError
|
||||
from sql_util.utils import SubqueryCount
|
||||
|
||||
import order.models
|
||||
import part.filters
|
||||
import stock.models
|
||||
import stock.serializers
|
||||
from common.settings import currency_code_mappings
|
||||
@ -248,7 +249,7 @@ class PurchaseOrderLineItemSerializer(InvenTreeModelSerializer):
|
||||
queryset = queryset.annotate(
|
||||
overdue=Case(
|
||||
When(
|
||||
Q(order__status__in=PurchaseOrderStatus.OPEN) & order.models.OrderLineItem.OVERDUE_FILTER, then=Value(True, output_field=BooleanField())
|
||||
Q(order__status__in=PurchaseOrderStatus.OPEN) & order.models.PurchaseOrderLineItem.OVERDUE_FILTER, then=Value(True, output_field=BooleanField())
|
||||
),
|
||||
default=Value(False, output_field=BooleanField()),
|
||||
)
|
||||
@ -790,17 +791,36 @@ class SalesOrderLineItemSerializer(InvenTreeModelSerializer):
|
||||
def annotate_queryset(queryset):
|
||||
"""Add some extra annotations to this queryset:
|
||||
|
||||
- "Overdue" status (boolean field)
|
||||
- "overdue" status (boolean field)
|
||||
- "available_quantity"
|
||||
"""
|
||||
|
||||
queryset = queryset.annotate(
|
||||
overdue=Case(
|
||||
When(
|
||||
Q(order__status__in=SalesOrderStatus.OPEN) & order.models.OrderLineItem.OVERDUE_FILTER, then=Value(True, output_field=BooleanField()),
|
||||
Q(order__status__in=SalesOrderStatus.OPEN) & order.models.SalesOrderLineItem.OVERDUE_FILTER, then=Value(True, output_field=BooleanField()),
|
||||
),
|
||||
default=Value(False, output_field=BooleanField()),
|
||||
)
|
||||
)
|
||||
|
||||
# Annotate each line with the available stock quantity
|
||||
# To do this, we need to look at the total stock and any allocations
|
||||
queryset = queryset.alias(
|
||||
total_stock=part.filters.annotate_total_stock(reference='part__'),
|
||||
allocated_to_sales_orders=part.filters.annotate_sales_order_allocations(reference='part__'),
|
||||
allocated_to_build_orders=part.filters.annotate_build_order_allocations(reference='part__'),
|
||||
)
|
||||
|
||||
queryset = queryset.annotate(
|
||||
available_stock=ExpressionWrapper(
|
||||
F('total_stock') - F('allocated_to_sales_orders') - F('allocated_to_build_orders'),
|
||||
output_field=models.DecimalField()
|
||||
)
|
||||
)
|
||||
|
||||
return queryset
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initializion routine for the serializer:
|
||||
|
||||
@ -825,7 +845,9 @@ class SalesOrderLineItemSerializer(InvenTreeModelSerializer):
|
||||
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
|
||||
allocations = SalesOrderAllocationSerializer(many=True, read_only=True, location_detail=True)
|
||||
|
||||
# Annotated fields
|
||||
overdue = serializers.BooleanField(required=False, read_only=True)
|
||||
available_stock = serializers.FloatField(read_only=True)
|
||||
|
||||
quantity = InvenTreeDecimalField()
|
||||
|
||||
@ -853,6 +875,7 @@ class SalesOrderLineItemSerializer(InvenTreeModelSerializer):
|
||||
'pk',
|
||||
'allocated',
|
||||
'allocations',
|
||||
'available_stock',
|
||||
'quantity',
|
||||
'reference',
|
||||
'notes',
|
||||
|
Reference in New Issue
Block a user