mirror of
https://github.com/inventree/InvenTree.git
synced 2025-10-25 02:17:37 +00:00
move filtering of serializer fields out of functions into mixin
This commit is contained in:
@@ -28,6 +28,52 @@ from common.currency import currency_code_default, currency_code_mappings
|
|||||||
from InvenTree.fields import InvenTreeRestURLField, InvenTreeURLField
|
from InvenTree.fields import InvenTreeRestURLField, InvenTreeURLField
|
||||||
|
|
||||||
|
|
||||||
|
# region path filtering
|
||||||
|
class OptionalFilterabelSerializer(serializers.Serializer):
|
||||||
|
"""Mixin to add context to serializer."""
|
||||||
|
|
||||||
|
is_filterable = None
|
||||||
|
is_filterable_default = None
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""Initialize the serializer."""
|
||||||
|
self.is_filterable = kwargs.pop('is_filterable', None)
|
||||||
|
self.is_filterable_default = kwargs.pop('is_filterable_default', True)
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class PathScopedMixin:
|
||||||
|
"""Mixin to disable a serializer field based on kwargs passed to the view."""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""Initialization routine for the serializer."""
|
||||||
|
flt_fld = {
|
||||||
|
k: a for k, a in self.fields.items() if getattr(a, 'is_filterable', None)
|
||||||
|
}
|
||||||
|
filter_targets = {k: kwargs.pop(k, False) for k in flt_fld}
|
||||||
|
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
if InvenTree.ready.isGeneratingSchema():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Throw out fields which are not requested
|
||||||
|
for k, v in filter_targets.items():
|
||||||
|
if v is not True:
|
||||||
|
self.fields.pop(k, None)
|
||||||
|
|
||||||
|
|
||||||
|
# Decorator for marking serialzier fields that can be filtered out
|
||||||
|
def can_filter(func, default=False):
|
||||||
|
"""Decorator for marking serializer fields as filterable."""
|
||||||
|
func._kwargs['is_filterable'] = True
|
||||||
|
func._kwargs['is_filterable_default'] = default
|
||||||
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
|
||||||
class EmptySerializer(serializers.Serializer):
|
class EmptySerializer(serializers.Serializer):
|
||||||
"""Empty serializer for use in testing."""
|
"""Empty serializer for use in testing."""
|
||||||
|
|
||||||
@@ -222,7 +268,9 @@ class DependentField(serializers.Field):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class InvenTreeModelSerializer(serializers.ModelSerializer):
|
class InvenTreeModelSerializer(
|
||||||
|
OptionalFilterabelSerializer, serializers.ModelSerializer
|
||||||
|
):
|
||||||
"""Inherits the standard Django ModelSerializer class, but also ensures that the underlying model class data are checked on validation."""
|
"""Inherits the standard Django ModelSerializer class, but also ensures that the underlying model class data are checked on validation."""
|
||||||
|
|
||||||
# Switch out URLField mapping
|
# Switch out URLField mapping
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ from InvenTree.serializers import (
|
|||||||
InvenTreeModelSerializer,
|
InvenTreeModelSerializer,
|
||||||
InvenTreeMoneySerializer,
|
InvenTreeMoneySerializer,
|
||||||
NotesFieldMixin,
|
NotesFieldMixin,
|
||||||
|
PathScopedMixin,
|
||||||
|
can_filter,
|
||||||
)
|
)
|
||||||
from order.status_codes import (
|
from order.status_codes import (
|
||||||
PurchaseOrderStatusGroups,
|
PurchaseOrderStatusGroups,
|
||||||
@@ -276,15 +278,6 @@ class AbstractExtraLineSerializer(
|
|||||||
):
|
):
|
||||||
"""Abstract Serializer for a ExtraLine object."""
|
"""Abstract Serializer for a ExtraLine object."""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Initialization routine for the serializer."""
|
|
||||||
order_detail = kwargs.pop('order_detail', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if order_detail is not True and not isGeneratingSchema():
|
|
||||||
self.fields.pop('order_detail', None)
|
|
||||||
|
|
||||||
quantity = serializers.FloatField()
|
quantity = serializers.FloatField()
|
||||||
|
|
||||||
price = InvenTreeMoneySerializer(allow_null=True)
|
price = InvenTreeMoneySerializer(allow_null=True)
|
||||||
@@ -343,15 +336,6 @@ class PurchaseOrderSerializer(
|
|||||||
'order_currency': {'required': False},
|
'order_currency': {'required': False},
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Initialization routine for the serializer."""
|
|
||||||
supplier_detail = kwargs.pop('supplier_detail', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if supplier_detail is not True and not isGeneratingSchema():
|
|
||||||
self.fields.pop('supplier_detail', None)
|
|
||||||
|
|
||||||
def skip_create_fields(self):
|
def skip_create_fields(self):
|
||||||
"""Skip these fields when instantiating a new object."""
|
"""Skip these fields when instantiating a new object."""
|
||||||
fields = super().skip_create_fields()
|
fields = super().skip_create_fields()
|
||||||
@@ -389,9 +373,11 @@ class PurchaseOrderSerializer(
|
|||||||
source='supplier.name', read_only=True, label=_('Supplier Name')
|
source='supplier.name', read_only=True, label=_('Supplier Name')
|
||||||
)
|
)
|
||||||
|
|
||||||
supplier_detail = CompanyBriefSerializer(
|
supplier_detail = can_filter(
|
||||||
|
CompanyBriefSerializer(
|
||||||
source='supplier', many=False, read_only=True, allow_null=True
|
source='supplier', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class OrderAdjustSerializer(serializers.Serializer):
|
class OrderAdjustSerializer(serializers.Serializer):
|
||||||
@@ -522,20 +508,17 @@ class PurchaseOrderLineItemSerializer(
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""Initialization routine for the serializer."""
|
"""Initialization routine for the serializer."""
|
||||||
part_detail = kwargs.pop('part_detail', False)
|
part_detail = kwargs.pop('part_detail', False)
|
||||||
order_detail = kwargs.pop('order_detail', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
if isGeneratingSchema():
|
if isGeneratingSchema():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# TODO INVE-T1 support complex filters
|
||||||
if part_detail is not True:
|
if part_detail is not True:
|
||||||
self.fields.pop('part_detail', None)
|
self.fields.pop('part_detail', None)
|
||||||
self.fields.pop('supplier_part_detail', None)
|
self.fields.pop('supplier_part_detail', None)
|
||||||
|
|
||||||
if order_detail is not True:
|
|
||||||
self.fields.pop('order_detail', None)
|
|
||||||
|
|
||||||
def skip_create_fields(self):
|
def skip_create_fields(self):
|
||||||
"""Return a list of fields to skip when creating a new object."""
|
"""Return a list of fields to skip when creating a new object."""
|
||||||
return ['auto_pricing', 'merge_items', *super().skip_create_fields()]
|
return ['auto_pricing', 'merge_items', *super().skip_create_fields()]
|
||||||
@@ -644,9 +627,11 @@ class PurchaseOrderLineItemSerializer(
|
|||||||
help_text=_('Purchase price currency')
|
help_text=_('Purchase price currency')
|
||||||
)
|
)
|
||||||
|
|
||||||
order_detail = PurchaseOrderSerializer(
|
order_detail = can_filter(
|
||||||
|
PurchaseOrderSerializer(
|
||||||
source='order', read_only=True, allow_null=True, many=False
|
source='order', read_only=True, allow_null=True, many=False
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
build_order_detail = build.serializers.BuildSerializer(
|
build_order_detail = build.serializers.BuildSerializer(
|
||||||
source='build_order', read_only=True, allow_null=True, many=False
|
source='build_order', read_only=True, allow_null=True, many=False
|
||||||
@@ -724,9 +709,11 @@ class PurchaseOrderExtraLineSerializer(
|
|||||||
):
|
):
|
||||||
"""Serializer for a PurchaseOrderExtraLine object."""
|
"""Serializer for a PurchaseOrderExtraLine object."""
|
||||||
|
|
||||||
order_detail = PurchaseOrderSerializer(
|
order_detail = can_filter(
|
||||||
|
PurchaseOrderSerializer(
|
||||||
source='order', many=False, read_only=True, allow_null=True
|
source='order', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
class Meta(AbstractExtraLineMeta):
|
class Meta(AbstractExtraLineMeta):
|
||||||
"""Metaclass options."""
|
"""Metaclass options."""
|
||||||
@@ -1009,15 +996,6 @@ class SalesOrderSerializer(
|
|||||||
|
|
||||||
extra_kwargs = {'order_currency': {'required': False}}
|
extra_kwargs = {'order_currency': {'required': False}}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Initialization routine for the serializer."""
|
|
||||||
customer_detail = kwargs.pop('customer_detail', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if customer_detail is not True and not isGeneratingSchema():
|
|
||||||
self.fields.pop('customer_detail', None)
|
|
||||||
|
|
||||||
def skip_create_fields(self):
|
def skip_create_fields(self):
|
||||||
"""Skip these fields when instantiating a new object."""
|
"""Skip these fields when instantiating a new object."""
|
||||||
fields = super().skip_create_fields()
|
fields = super().skip_create_fields()
|
||||||
@@ -1058,9 +1036,11 @@ class SalesOrderSerializer(
|
|||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
customer_detail = CompanyBriefSerializer(
|
customer_detail = can_filter(
|
||||||
|
CompanyBriefSerializer(
|
||||||
source='customer', many=False, read_only=True, allow_null=True
|
source='customer', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
shipments_count = serializers.IntegerField(
|
shipments_count = serializers.IntegerField(
|
||||||
read_only=True, allow_null=True, label=_('Shipments')
|
read_only=True, allow_null=True, label=_('Shipments')
|
||||||
@@ -1083,6 +1063,7 @@ class SalesOrderIssueSerializer(OrderAdjustSerializer):
|
|||||||
class SalesOrderLineItemSerializer(
|
class SalesOrderLineItemSerializer(
|
||||||
DataImportExportSerializerMixin,
|
DataImportExportSerializerMixin,
|
||||||
AbstractLineItemSerializer,
|
AbstractLineItemSerializer,
|
||||||
|
PathScopedMixin,
|
||||||
InvenTreeModelSerializer,
|
InvenTreeModelSerializer,
|
||||||
):
|
):
|
||||||
"""Serializer for a SalesOrderLineItem object."""
|
"""Serializer for a SalesOrderLineItem object."""
|
||||||
@@ -1116,29 +1097,6 @@ class SalesOrderLineItemSerializer(
|
|||||||
'on_order',
|
'on_order',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Initialization routine for the serializer.
|
|
||||||
|
|
||||||
- Add extra related serializer information if required
|
|
||||||
"""
|
|
||||||
part_detail = kwargs.pop('part_detail', False)
|
|
||||||
order_detail = kwargs.pop('order_detail', False)
|
|
||||||
customer_detail = kwargs.pop('customer_detail', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if isGeneratingSchema():
|
|
||||||
return
|
|
||||||
|
|
||||||
if part_detail is not True:
|
|
||||||
self.fields.pop('part_detail', None)
|
|
||||||
|
|
||||||
if order_detail is not True:
|
|
||||||
self.fields.pop('order_detail', None)
|
|
||||||
|
|
||||||
if customer_detail is not True:
|
|
||||||
self.fields.pop('customer_detail', None)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def annotate_queryset(queryset):
|
def annotate_queryset(queryset):
|
||||||
"""Add some extra annotations to this queryset.
|
"""Add some extra annotations to this queryset.
|
||||||
@@ -1236,15 +1194,19 @@ class SalesOrderLineItemSerializer(
|
|||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
order_detail = SalesOrderSerializer(
|
order_detail = can_filter(
|
||||||
|
SalesOrderSerializer(
|
||||||
source='order', many=False, read_only=True, allow_null=True
|
source='order', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
part_detail = PartBriefSerializer(
|
|
||||||
source='part', many=False, read_only=True, allow_null=True
|
|
||||||
)
|
)
|
||||||
customer_detail = CompanyBriefSerializer(
|
part_detail = can_filter(
|
||||||
|
PartBriefSerializer(source='part', many=False, read_only=True, allow_null=True)
|
||||||
|
)
|
||||||
|
customer_detail = can_filter(
|
||||||
|
CompanyBriefSerializer(
|
||||||
source='order.customer', many=False, read_only=True, allow_null=True
|
source='order.customer', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Annotated fields
|
# Annotated fields
|
||||||
overdue = serializers.BooleanField(read_only=True, allow_null=True)
|
overdue = serializers.BooleanField(read_only=True, allow_null=True)
|
||||||
@@ -1291,15 +1253,6 @@ class SalesOrderShipmentSerializer(NotesFieldMixin, InvenTreeModelSerializer):
|
|||||||
'notes',
|
'notes',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Initialization routine for the serializer."""
|
|
||||||
order_detail = kwargs.pop('order_detail', True)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if not order_detail and not isGeneratingSchema():
|
|
||||||
self.fields.pop('order_detail', None)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def annotate_queryset(queryset):
|
def annotate_queryset(queryset):
|
||||||
"""Annotate the queryset with extra information."""
|
"""Annotate the queryset with extra information."""
|
||||||
@@ -1314,8 +1267,11 @@ class SalesOrderShipmentSerializer(NotesFieldMixin, InvenTreeModelSerializer):
|
|||||||
read_only=True, allow_null=True, label=_('Allocated Items')
|
read_only=True, allow_null=True, label=_('Allocated Items')
|
||||||
)
|
)
|
||||||
|
|
||||||
order_detail = SalesOrderSerializer(
|
order_detail = can_filter(
|
||||||
|
SalesOrderSerializer(
|
||||||
source='order', read_only=True, allow_null=True, many=False
|
source='order', read_only=True, allow_null=True, many=False
|
||||||
|
),
|
||||||
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -1352,34 +1308,6 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
read_only_fields = ['line', '']
|
read_only_fields = ['line', '']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Initialization routine for the serializer."""
|
|
||||||
order_detail = kwargs.pop('order_detail', False)
|
|
||||||
part_detail = kwargs.pop('part_detail', True)
|
|
||||||
item_detail = kwargs.pop('item_detail', True)
|
|
||||||
location_detail = kwargs.pop('location_detail', False)
|
|
||||||
customer_detail = kwargs.pop('customer_detail', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if isGeneratingSchema():
|
|
||||||
return
|
|
||||||
|
|
||||||
if not order_detail:
|
|
||||||
self.fields.pop('order_detail', None)
|
|
||||||
|
|
||||||
if not part_detail:
|
|
||||||
self.fields.pop('part_detail', None)
|
|
||||||
|
|
||||||
if not item_detail:
|
|
||||||
self.fields.pop('item_detail', None)
|
|
||||||
|
|
||||||
if not location_detail:
|
|
||||||
self.fields.pop('location_detail', None)
|
|
||||||
|
|
||||||
if not customer_detail:
|
|
||||||
self.fields.pop('customer_detail', None)
|
|
||||||
|
|
||||||
part = serializers.PrimaryKeyRelatedField(source='item.part', read_only=True)
|
part = serializers.PrimaryKeyRelatedField(source='item.part', read_only=True)
|
||||||
order = serializers.PrimaryKeyRelatedField(
|
order = serializers.PrimaryKeyRelatedField(
|
||||||
source='line.order', many=False, read_only=True
|
source='line.order', many=False, read_only=True
|
||||||
@@ -1391,13 +1319,19 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Extra detail fields
|
# Extra detail fields
|
||||||
order_detail = SalesOrderSerializer(
|
order_detail = can_filter(
|
||||||
|
SalesOrderSerializer(
|
||||||
source='line.order', many=False, read_only=True, allow_null=True
|
source='line.order', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
part_detail = PartBriefSerializer(
|
|
||||||
source='item.part', many=False, read_only=True, allow_null=True
|
|
||||||
)
|
)
|
||||||
item_detail = stock.serializers.StockItemSerializer(
|
part_detail = can_filter(
|
||||||
|
PartBriefSerializer(
|
||||||
|
source='item.part', many=False, read_only=True, allow_null=True
|
||||||
|
),
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
item_detail = can_filter(
|
||||||
|
stock.serializers.StockItemSerializer(
|
||||||
source='item',
|
source='item',
|
||||||
many=False,
|
many=False,
|
||||||
read_only=True,
|
read_only=True,
|
||||||
@@ -1405,13 +1339,19 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer):
|
|||||||
part_detail=False,
|
part_detail=False,
|
||||||
location_detail=False,
|
location_detail=False,
|
||||||
supplier_part_detail=False,
|
supplier_part_detail=False,
|
||||||
|
),
|
||||||
|
True,
|
||||||
)
|
)
|
||||||
location_detail = stock.serializers.LocationBriefSerializer(
|
location_detail = can_filter(
|
||||||
|
stock.serializers.LocationBriefSerializer(
|
||||||
source='item.location', many=False, read_only=True, allow_null=True
|
source='item.location', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
customer_detail = CompanyBriefSerializer(
|
)
|
||||||
|
customer_detail = can_filter(
|
||||||
|
CompanyBriefSerializer(
|
||||||
source='line.order.customer', many=False, read_only=True, allow_null=True
|
source='line.order.customer', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
shipment_detail = SalesOrderShipmentSerializer(
|
shipment_detail = SalesOrderShipmentSerializer(
|
||||||
source='shipment',
|
source='shipment',
|
||||||
@@ -1860,9 +1800,11 @@ class SalesOrderExtraLineSerializer(
|
|||||||
|
|
||||||
model = order.models.SalesOrderExtraLine
|
model = order.models.SalesOrderExtraLine
|
||||||
|
|
||||||
order_detail = SalesOrderSerializer(
|
order_detail = can_filter(
|
||||||
|
SalesOrderSerializer(
|
||||||
source='order', many=False, read_only=True, allow_null=True
|
source='order', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@register_importer()
|
@register_importer()
|
||||||
@@ -1891,15 +1833,6 @@ class ReturnOrderSerializer(
|
|||||||
|
|
||||||
read_only_fields = ['creation_date']
|
read_only_fields = ['creation_date']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Initialization routine for the serializer."""
|
|
||||||
customer_detail = kwargs.pop('customer_detail', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if customer_detail is not True and not isGeneratingSchema():
|
|
||||||
self.fields.pop('customer_detail', None)
|
|
||||||
|
|
||||||
def skip_create_fields(self):
|
def skip_create_fields(self):
|
||||||
"""Skip these fields when instantiating a new object."""
|
"""Skip these fields when instantiating a new object."""
|
||||||
fields = super().skip_create_fields()
|
fields = super().skip_create_fields()
|
||||||
@@ -1929,9 +1862,11 @@ class ReturnOrderSerializer(
|
|||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
customer_detail = CompanyBriefSerializer(
|
customer_detail = can_filter(
|
||||||
|
CompanyBriefSerializer(
|
||||||
source='customer', many=False, read_only=True, allow_null=True
|
source='customer', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ReturnOrderHoldSerializer(OrderAdjustSerializer):
|
class ReturnOrderHoldSerializer(OrderAdjustSerializer):
|
||||||
@@ -2096,41 +2031,27 @@ class ReturnOrderLineItemSerializer(
|
|||||||
'link',
|
'link',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
order_detail = can_filter(
|
||||||
"""Initialization routine for the serializer."""
|
ReturnOrderSerializer(
|
||||||
order_detail = kwargs.pop('order_detail', False)
|
|
||||||
item_detail = kwargs.pop('item_detail', False)
|
|
||||||
part_detail = kwargs.pop('part_detail', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if isGeneratingSchema():
|
|
||||||
return
|
|
||||||
|
|
||||||
if not order_detail:
|
|
||||||
self.fields.pop('order_detail', None)
|
|
||||||
|
|
||||||
if not item_detail:
|
|
||||||
self.fields.pop('item_detail', None)
|
|
||||||
|
|
||||||
if not part_detail:
|
|
||||||
self.fields.pop('part_detail', None)
|
|
||||||
|
|
||||||
order_detail = ReturnOrderSerializer(
|
|
||||||
source='order', many=False, read_only=True, allow_null=True
|
source='order', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
quantity = serializers.FloatField(
|
quantity = serializers.FloatField(
|
||||||
label=_('Quantity'), help_text=_('Quantity to return')
|
label=_('Quantity'), help_text=_('Quantity to return')
|
||||||
)
|
)
|
||||||
|
|
||||||
item_detail = stock.serializers.StockItemSerializer(
|
item_detail = can_filter(
|
||||||
|
stock.serializers.StockItemSerializer(
|
||||||
source='item', many=False, read_only=True, allow_null=True
|
source='item', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
part_detail = PartBriefSerializer(
|
part_detail = can_filter(
|
||||||
|
PartBriefSerializer(
|
||||||
source='item.part', many=False, read_only=True, allow_null=True
|
source='item.part', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
price = InvenTreeMoneySerializer(allow_null=True)
|
price = InvenTreeMoneySerializer(allow_null=True)
|
||||||
price_currency = InvenTreeCurrencySerializer(help_text=_('Line price currency'))
|
price_currency = InvenTreeCurrencySerializer(help_text=_('Line price currency'))
|
||||||
@@ -2147,6 +2068,8 @@ class ReturnOrderExtraLineSerializer(
|
|||||||
|
|
||||||
model = order.models.ReturnOrderExtraLine
|
model = order.models.ReturnOrderExtraLine
|
||||||
|
|
||||||
order_detail = ReturnOrderSerializer(
|
order_detail = can_filter(
|
||||||
|
ReturnOrderSerializer(
|
||||||
source='order', many=False, read_only=True, allow_null=True
|
source='order', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import users.models
|
|||||||
from importer.registry import register_importer
|
from importer.registry import register_importer
|
||||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||||
from InvenTree.ready import isGeneratingSchema
|
from InvenTree.ready import isGeneratingSchema
|
||||||
|
from InvenTree.serializers import can_filter
|
||||||
from users.serializers import UserSerializer
|
from users.serializers import UserSerializer
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
@@ -91,6 +92,7 @@ class CategorySerializer(
|
|||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# TODO INVE-T1 support complex filters
|
||||||
if not path_detail and not isGeneratingSchema():
|
if not path_detail and not isGeneratingSchema():
|
||||||
self.fields.pop('path', None)
|
self.fields.pop('path', None)
|
||||||
|
|
||||||
@@ -355,6 +357,7 @@ class PartBriefSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# TODO INVE-T1 support complex filters
|
||||||
if not pricing and not isGeneratingSchema():
|
if not pricing and not isGeneratingSchema():
|
||||||
self.fields.pop('pricing_min', None)
|
self.fields.pop('pricing_min', None)
|
||||||
self.fields.pop('pricing_max', None)
|
self.fields.pop('pricing_max', None)
|
||||||
@@ -414,25 +417,6 @@ class PartParameterSerializer(
|
|||||||
|
|
||||||
read_only_fields = ['updated', 'updated_by']
|
read_only_fields = ['updated', 'updated_by']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Custom initialization method for the serializer.
|
|
||||||
|
|
||||||
Allows us to optionally include or exclude particular information
|
|
||||||
"""
|
|
||||||
template_detail = kwargs.pop('template_detail', True)
|
|
||||||
part_detail = kwargs.pop('part_detail', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if isGeneratingSchema():
|
|
||||||
return
|
|
||||||
|
|
||||||
if not part_detail:
|
|
||||||
self.fields.pop('part_detail', None)
|
|
||||||
|
|
||||||
if not template_detail:
|
|
||||||
self.fields.pop('template_detail', None)
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""Save the PartParameter instance."""
|
"""Save the PartParameter instance."""
|
||||||
instance = super().save()
|
instance = super().save()
|
||||||
@@ -444,12 +428,15 @@ class PartParameterSerializer(
|
|||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
part_detail = PartBriefSerializer(
|
part_detail = can_filter(
|
||||||
source='part', many=False, read_only=True, allow_null=True
|
PartBriefSerializer(source='part', many=False, read_only=True, allow_null=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
template_detail = PartParameterTemplateSerializer(
|
template_detail = can_filter(
|
||||||
|
PartParameterTemplateSerializer(
|
||||||
source='template', many=False, read_only=True, allow_null=True
|
source='template', many=False, read_only=True, allow_null=True
|
||||||
|
),
|
||||||
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
updated_by_detail = UserSerializer(
|
updated_by_detail = UserSerializer(
|
||||||
@@ -737,9 +724,7 @@ class PartSerializer(
|
|||||||
- Allows us to optionally pass extra fields based on the query.
|
- Allows us to optionally pass extra fields based on the query.
|
||||||
"""
|
"""
|
||||||
self.starred_parts = kwargs.pop('starred_parts', [])
|
self.starred_parts = kwargs.pop('starred_parts', [])
|
||||||
category_detail = kwargs.pop('category_detail', False)
|
|
||||||
location_detail = kwargs.pop('location_detail', False)
|
location_detail = kwargs.pop('location_detail', False)
|
||||||
parameters = kwargs.pop('parameters', False)
|
|
||||||
create = kwargs.pop('create', False)
|
create = kwargs.pop('create', False)
|
||||||
pricing = kwargs.pop('pricing', True)
|
pricing = kwargs.pop('pricing', True)
|
||||||
path_detail = kwargs.pop('path_detail', False)
|
path_detail = kwargs.pop('path_detail', False)
|
||||||
@@ -749,15 +734,11 @@ class PartSerializer(
|
|||||||
if isGeneratingSchema():
|
if isGeneratingSchema():
|
||||||
return
|
return
|
||||||
|
|
||||||
if not category_detail:
|
# TODO INVE-T1 support complex filters
|
||||||
self.fields.pop('category_detail', None)
|
|
||||||
|
|
||||||
if not location_detail:
|
if not location_detail:
|
||||||
self.fields.pop('default_location_detail', None)
|
self.fields.pop('default_location_detail', None)
|
||||||
|
|
||||||
if not parameters:
|
# TODO INVE-T1 support complex filters
|
||||||
self.fields.pop('parameters', None)
|
|
||||||
|
|
||||||
if not path_detail:
|
if not path_detail:
|
||||||
self.fields.pop('category_path', None)
|
self.fields.pop('category_path', None)
|
||||||
|
|
||||||
@@ -769,6 +750,7 @@ class PartSerializer(
|
|||||||
continue
|
continue
|
||||||
self.fields.pop(f, None)
|
self.fields.pop(f, None)
|
||||||
|
|
||||||
|
# TODO INVE-T1 support complex filters
|
||||||
if not pricing:
|
if not pricing:
|
||||||
self.fields.pop('pricing_min', None)
|
self.fields.pop('pricing_min', None)
|
||||||
self.fields.pop('pricing_max', None)
|
self.fields.pop('pricing_max', None)
|
||||||
@@ -888,9 +870,11 @@ class PartSerializer(
|
|||||||
return part in self.starred_parts
|
return part in self.starred_parts
|
||||||
|
|
||||||
# Extra detail for the category
|
# Extra detail for the category
|
||||||
category_detail = CategorySerializer(
|
category_detail = can_filter(
|
||||||
|
CategorySerializer(
|
||||||
source='category', many=False, read_only=True, allow_null=True
|
source='category', many=False, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
category_path = serializers.ListField(
|
category_path = serializers.ListField(
|
||||||
child=serializers.DictField(),
|
child=serializers.DictField(),
|
||||||
@@ -1018,7 +1002,9 @@ class PartSerializer(
|
|||||||
source='pricing_data.updated', allow_null=True, read_only=True
|
source='pricing_data.updated', allow_null=True, read_only=True
|
||||||
)
|
)
|
||||||
|
|
||||||
parameters = PartParameterSerializer(many=True, read_only=True, allow_null=True)
|
parameters = can_filter(
|
||||||
|
PartParameterSerializer(many=True, read_only=True, allow_null=True)
|
||||||
|
)
|
||||||
|
|
||||||
# Extra fields used only for creation of a new Part instance
|
# Extra fields used only for creation of a new Part instance
|
||||||
duplicate = DuplicatePartSerializer(
|
duplicate = DuplicatePartSerializer(
|
||||||
@@ -1649,29 +1635,14 @@ class BomItemSerializer(
|
|||||||
- 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
|
||||||
"""
|
"""
|
||||||
can_build = kwargs.pop('can_build', True)
|
|
||||||
part_detail = kwargs.pop('part_detail', False)
|
|
||||||
sub_part_detail = kwargs.pop('sub_part_detail', True)
|
|
||||||
pricing = kwargs.pop('pricing', True)
|
pricing = kwargs.pop('pricing', True)
|
||||||
substitutes = kwargs.pop('substitutes', True)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
if isGeneratingSchema():
|
if isGeneratingSchema():
|
||||||
return
|
return
|
||||||
|
|
||||||
if not part_detail:
|
# TODO INVE-T1 support complex filters
|
||||||
self.fields.pop('part_detail', None)
|
|
||||||
|
|
||||||
if not sub_part_detail:
|
|
||||||
self.fields.pop('sub_part_detail', None)
|
|
||||||
|
|
||||||
if not can_build:
|
|
||||||
self.fields.pop('can_build')
|
|
||||||
|
|
||||||
if not substitutes:
|
|
||||||
self.fields.pop('substitutes', None)
|
|
||||||
|
|
||||||
if not pricing:
|
if not pricing:
|
||||||
self.fields.pop('pricing_min', None)
|
self.fields.pop('pricing_min', None)
|
||||||
self.fields.pop('pricing_max', None)
|
self.fields.pop('pricing_max', None)
|
||||||
@@ -1702,12 +1673,18 @@ class BomItemSerializer(
|
|||||||
help_text=_('Select the parent assembly'),
|
help_text=_('Select the parent assembly'),
|
||||||
)
|
)
|
||||||
|
|
||||||
substitutes = BomItemSubstituteSerializer(
|
substitutes = can_filter(
|
||||||
many=True, read_only=True, allow_null=True
|
BomItemSubstituteSerializer(many=True, read_only=True, allow_null=True), True
|
||||||
)
|
)
|
||||||
|
|
||||||
part_detail = PartBriefSerializer(
|
part_detail = can_filter(
|
||||||
source='part', label=_('Assembly'), many=False, read_only=True, allow_null=True
|
PartBriefSerializer(
|
||||||
|
source='part',
|
||||||
|
label=_('Assembly'),
|
||||||
|
many=False,
|
||||||
|
read_only=True,
|
||||||
|
allow_null=True,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
sub_part = serializers.PrimaryKeyRelatedField(
|
sub_part = serializers.PrimaryKeyRelatedField(
|
||||||
@@ -1716,12 +1693,15 @@ class BomItemSerializer(
|
|||||||
help_text=_('Select the component part'),
|
help_text=_('Select the component part'),
|
||||||
)
|
)
|
||||||
|
|
||||||
sub_part_detail = PartBriefSerializer(
|
sub_part_detail = can_filter(
|
||||||
|
PartBriefSerializer(
|
||||||
source='sub_part',
|
source='sub_part',
|
||||||
label=_('Component'),
|
label=_('Component'),
|
||||||
many=False,
|
many=False,
|
||||||
read_only=True,
|
read_only=True,
|
||||||
allow_null=True,
|
allow_null=True,
|
||||||
|
),
|
||||||
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
on_order = serializers.FloatField(
|
on_order = serializers.FloatField(
|
||||||
@@ -1732,8 +1712,9 @@ class BomItemSerializer(
|
|||||||
label=_('In Production'), read_only=True, allow_null=True
|
label=_('In Production'), read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
|
||||||
can_build = serializers.FloatField(
|
can_build = can_filter(
|
||||||
label=_('Can Build'), read_only=True, allow_null=True
|
serializers.FloatField(label=_('Can Build'), read_only=True, allow_null=True),
|
||||||
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Cached pricing fields
|
# Cached pricing fields
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ from InvenTree.serializers import (
|
|||||||
InvenTreeCurrencySerializer,
|
InvenTreeCurrencySerializer,
|
||||||
InvenTreeDecimalField,
|
InvenTreeDecimalField,
|
||||||
InvenTreeModelSerializer,
|
InvenTreeModelSerializer,
|
||||||
|
PathScopedMixin,
|
||||||
|
can_filter,
|
||||||
)
|
)
|
||||||
from users.serializers import UserSerializer
|
from users.serializers import UserSerializer
|
||||||
|
|
||||||
@@ -222,23 +224,9 @@ class StockItemTestResultSerializer(
|
|||||||
|
|
||||||
read_only_fields = ['pk', 'user', 'date']
|
read_only_fields = ['pk', 'user', 'date']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
user_detail = can_filter(
|
||||||
"""Add detail fields."""
|
UserSerializer(source='user', read_only=True, allow_null=True)
|
||||||
user_detail = kwargs.pop('user_detail', False)
|
)
|
||||||
template_detail = kwargs.pop('template_detail', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if isGeneratingSchema():
|
|
||||||
return
|
|
||||||
|
|
||||||
if user_detail is not True:
|
|
||||||
self.fields.pop('user_detail', None)
|
|
||||||
|
|
||||||
if template_detail is not True:
|
|
||||||
self.fields.pop('template_detail', None)
|
|
||||||
|
|
||||||
user_detail = UserSerializer(source='user', read_only=True, allow_null=True)
|
|
||||||
|
|
||||||
template = serializers.PrimaryKeyRelatedField(
|
template = serializers.PrimaryKeyRelatedField(
|
||||||
queryset=part_models.PartTestTemplate.objects.all(),
|
queryset=part_models.PartTestTemplate.objects.all(),
|
||||||
@@ -249,9 +237,11 @@ class StockItemTestResultSerializer(
|
|||||||
label=_('Test template for this result'),
|
label=_('Test template for this result'),
|
||||||
)
|
)
|
||||||
|
|
||||||
template_detail = part_serializers.PartTestTemplateSerializer(
|
template_detail = can_filter(
|
||||||
|
part_serializers.PartTestTemplateSerializer(
|
||||||
source='template', read_only=True, allow_null=True
|
source='template', read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
attachment = InvenTree.serializers.InvenTreeAttachmentSerializerField(
|
attachment = InvenTree.serializers.InvenTreeAttachmentSerializerField(
|
||||||
required=False,
|
required=False,
|
||||||
@@ -415,30 +405,14 @@ class StockItemSerializer(
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""Add detail fields."""
|
"""Add detail fields."""
|
||||||
part_detail = kwargs.pop('part_detail', True)
|
|
||||||
location_detail = kwargs.pop('location_detail', True)
|
|
||||||
supplier_part_detail = kwargs.pop('supplier_part_detail', True)
|
|
||||||
path_detail = kwargs.pop('path_detail', False)
|
path_detail = kwargs.pop('path_detail', False)
|
||||||
|
|
||||||
tests = kwargs.pop('tests', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
if isGeneratingSchema():
|
if isGeneratingSchema():
|
||||||
return
|
return
|
||||||
|
|
||||||
if not part_detail:
|
# TODO INVE-T1 support complex filters
|
||||||
self.fields.pop('part_detail', None)
|
|
||||||
|
|
||||||
if not location_detail:
|
|
||||||
self.fields.pop('location_detail', None)
|
|
||||||
|
|
||||||
if not supplier_part_detail:
|
|
||||||
self.fields.pop('supplier_part_detail', None)
|
|
||||||
|
|
||||||
if not tests:
|
|
||||||
self.fields.pop('tests', None)
|
|
||||||
|
|
||||||
if not path_detail:
|
if not path_detail:
|
||||||
self.fields.pop('location_path', None)
|
self.fields.pop('location_path', None)
|
||||||
|
|
||||||
@@ -613,7 +587,8 @@ class StockItemSerializer(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Optional detail fields, which can be appended via query parameters
|
# Optional detail fields, which can be appended via query parameters
|
||||||
supplier_part_detail = company_serializers.SupplierPartSerializer(
|
supplier_part_detail = can_filter(
|
||||||
|
company_serializers.SupplierPartSerializer(
|
||||||
label=_('Supplier Part'),
|
label=_('Supplier Part'),
|
||||||
source='supplier_part',
|
source='supplier_part',
|
||||||
brief=True,
|
brief=True,
|
||||||
@@ -623,23 +598,33 @@ class StockItemSerializer(
|
|||||||
many=False,
|
many=False,
|
||||||
read_only=True,
|
read_only=True,
|
||||||
allow_null=True,
|
allow_null=True,
|
||||||
|
),
|
||||||
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
part_detail = part_serializers.PartBriefSerializer(
|
part_detail = can_filter(
|
||||||
|
part_serializers.PartBriefSerializer(
|
||||||
label=_('Part'), source='part', many=False, read_only=True, allow_null=True
|
label=_('Part'), source='part', many=False, read_only=True, allow_null=True
|
||||||
|
),
|
||||||
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
location_detail = LocationBriefSerializer(
|
location_detail = can_filter(
|
||||||
|
LocationBriefSerializer(
|
||||||
label=_('Location'),
|
label=_('Location'),
|
||||||
source='location',
|
source='location',
|
||||||
many=False,
|
many=False,
|
||||||
read_only=True,
|
read_only=True,
|
||||||
allow_null=True,
|
allow_null=True,
|
||||||
|
),
|
||||||
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
tests = StockItemTestResultSerializer(
|
tests = can_filter(
|
||||||
|
StockItemTestResultSerializer(
|
||||||
source='test_results', many=True, read_only=True, allow_null=True
|
source='test_results', many=True, read_only=True, allow_null=True
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
quantity = InvenTreeDecimalField()
|
quantity = InvenTreeDecimalField()
|
||||||
|
|
||||||
@@ -1189,6 +1174,7 @@ class LocationSerializer(
|
|||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# TODO INVE-T1 support complex filters
|
||||||
if not path_detail and not isGeneratingSchema():
|
if not path_detail and not isGeneratingSchema():
|
||||||
self.fields.pop('path', None)
|
self.fields.pop('path', None)
|
||||||
|
|
||||||
@@ -1241,7 +1227,9 @@ class LocationSerializer(
|
|||||||
|
|
||||||
@register_importer()
|
@register_importer()
|
||||||
class StockTrackingSerializer(
|
class StockTrackingSerializer(
|
||||||
DataImportExportSerializerMixin, InvenTree.serializers.InvenTreeModelSerializer
|
DataImportExportSerializerMixin,
|
||||||
|
PathScopedMixin,
|
||||||
|
InvenTree.serializers.InvenTreeModelSerializer,
|
||||||
):
|
):
|
||||||
"""Serializer for StockItemTracking model."""
|
"""Serializer for StockItemTracking model."""
|
||||||
|
|
||||||
@@ -1264,30 +1252,14 @@ class StockTrackingSerializer(
|
|||||||
|
|
||||||
read_only_fields = ['date', 'user', 'label', 'tracking_type']
|
read_only_fields = ['date', 'user', 'label', 'tracking_type']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Add detail fields."""
|
|
||||||
item_detail = kwargs.pop('item_detail', False)
|
|
||||||
user_detail = kwargs.pop('user_detail', False)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if isGeneratingSchema():
|
|
||||||
return
|
|
||||||
|
|
||||||
if item_detail is not True:
|
|
||||||
self.fields.pop('item_detail', None)
|
|
||||||
|
|
||||||
if user_detail is not True:
|
|
||||||
self.fields.pop('user_detail', None)
|
|
||||||
|
|
||||||
label = serializers.CharField(read_only=True)
|
label = serializers.CharField(read_only=True)
|
||||||
|
|
||||||
item_detail = StockItemSerializer(
|
item_detail = can_filter(
|
||||||
source='item', many=False, read_only=True, allow_null=True
|
StockItemSerializer(source='item', many=False, read_only=True, allow_null=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
user_detail = UserSerializer(
|
user_detail = can_filter(
|
||||||
source='user', many=False, read_only=True, allow_null=True
|
UserSerializer(source='user', many=False, read_only=True, allow_null=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
deltas = serializers.JSONField(read_only=True)
|
deltas = serializers.JSONField(read_only=True)
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ class GroupSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""Initialize this serializer with extra fields as required."""
|
"""Initialize this serializer with extra fields as required."""
|
||||||
|
# TODO INVE-T1 support complex filters
|
||||||
role_detail = kwargs.pop('role_detail', False)
|
role_detail = kwargs.pop('role_detail', False)
|
||||||
user_detail = kwargs.pop('user_detail', False)
|
user_detail = kwargs.pop('user_detail', False)
|
||||||
permission_detail = kwargs.pop('permission_detail', False)
|
permission_detail = kwargs.pop('permission_detail', False)
|
||||||
|
|||||||
Reference in New Issue
Block a user