mirror of
https://github.com/inventree/InvenTree.git
synced 2025-10-25 02:17:37 +00:00
adjust naming and docs, add typing to clean stuff up
This commit is contained in:
@@ -14,7 +14,7 @@ from InvenTree.helpers import (
|
||||
strip_html_tags,
|
||||
)
|
||||
from InvenTree.schema import schema_for_view_output_options
|
||||
from InvenTree.serializers import PathScopedMixin
|
||||
from InvenTree.serializers import FilterableSerializerMixin
|
||||
|
||||
|
||||
class CleanMixin:
|
||||
@@ -231,9 +231,9 @@ class OutputOptionsMixin:
|
||||
serializer = super().get_serializer(*args, **kwargs)
|
||||
|
||||
# Check if the serializer actually can be filtered - makes not much sense to use this mixin without that prerequisite
|
||||
if not isinstance(serializer, PathScopedMixin):
|
||||
if not isinstance(serializer, FilterableSerializerMixin):
|
||||
raise Exception(
|
||||
'INVE-W999: `OutputOptionsMixin` can only be used with serializers that contain the `PathScopedMixin` mixin'
|
||||
'INVE-I2: `OutputOptionsMixin` can only be used with serializers that contain the `FilterableSerializerMixin` mixin'
|
||||
)
|
||||
|
||||
return serializer
|
||||
|
||||
@@ -4,7 +4,7 @@ import os
|
||||
from collections import OrderedDict
|
||||
from copy import deepcopy
|
||||
from decimal import Decimal
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||
@@ -31,8 +31,11 @@ from InvenTree.helpers import str2bool
|
||||
|
||||
|
||||
# region path filtering
|
||||
class OptFilter:
|
||||
"""Filter for serializer or field."""
|
||||
class FilterableSerializerField:
|
||||
"""Mixin to mark serializer as filterable.
|
||||
|
||||
This needs to be used in conjunction with `enable_filter` on the serializer field!
|
||||
"""
|
||||
|
||||
is_filterable = None
|
||||
is_filterable_vals = {}
|
||||
@@ -45,15 +48,47 @@ class OptFilter:
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class PathScopedMixin:
|
||||
"""Mixin to disable a serializer field based on kwargs passed to the view."""
|
||||
def enable_filter(
|
||||
func: Any, default_include: bool = False, filter_name: Optional[str] = None
|
||||
):
|
||||
"""Decorator for marking a serializer field as filterable.
|
||||
|
||||
This can be customized by passing in arguments. This only works in conjunction with serializer fields or serializers that contain the `FilterableSerializerField` mixin.
|
||||
|
||||
Args:
|
||||
func: The serializer field to mark as filterable. Will automatically be passed when used as a decorator.
|
||||
default_include (bool): If True, the field will be included by default unless explicitly excluded. If False, the field will be excluded by default unless explicitly included.
|
||||
filter_name (str, optional): The name of the filter parameter to use in the URL. If None, the function name of the (decorated) function will be used.
|
||||
"""
|
||||
# Ensure this function can be actually filteres
|
||||
if not issubclass(func.__class__, FilterableSerializerField):
|
||||
raise TypeError(
|
||||
'INVE-I2: `enable_filter` can only be applied to serializer fields / serializers that contain the `FilterableSerializerField` mixin!'
|
||||
)
|
||||
|
||||
# Mark the function as filterable
|
||||
func._kwargs['is_filterable'] = True
|
||||
func._kwargs['is_filterable_vals'] = {
|
||||
'default': default_include,
|
||||
'filter_name': filter_name if filter_name else func.field_name,
|
||||
}
|
||||
return func
|
||||
|
||||
|
||||
class FilterableSerializerMixin:
|
||||
"""Mixin that enables filtering of marked fields on a serializer.
|
||||
|
||||
Use the `enable_filter` decorator to mark serializer fields as filterable.
|
||||
This introduces overhead during initialization, so only use this mixin when necessary.
|
||||
If you need to mark a serializer as filterable but it does not contain any filterable fields, set `no_filters = True` to avoid getting an exception that protects against over-application of this mixin.
|
||||
"""
|
||||
|
||||
_was_filtered = False
|
||||
no_filters = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialization routine for the serializer."""
|
||||
# add list_serializer_class to meta if not present
|
||||
"""Initialization routine for the serializer. This gathers and applies filters through kwargs."""
|
||||
# add list_serializer_class to meta if not present - reduces duplication
|
||||
if not isinstance(self, FilterableListSerializer) and (
|
||||
not hasattr(self.Meta, 'list_serializer_class')
|
||||
):
|
||||
@@ -61,98 +96,90 @@ class PathScopedMixin:
|
||||
|
||||
self.gather_filters(kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.do_filtering(*args, **kwargs)
|
||||
self.do_filtering()
|
||||
|
||||
def gather_filters(self, kwargs):
|
||||
"""Gather filterable fields."""
|
||||
def gather_filters(self, kwargs) -> None:
|
||||
"""Gather filterable fields through introspection."""
|
||||
# Fast exit if this has already been done or would not have any effect
|
||||
if getattr(self, '_was_filtered', False) or not hasattr(self, 'fields'):
|
||||
return kwargs
|
||||
return
|
||||
self._was_filtered = True
|
||||
|
||||
# Actually gather the filterable fields
|
||||
fields = self.fields.items()
|
||||
self.filter_targets = {
|
||||
k: {'serializer': a, **getattr(a, 'is_filterable_vals', {})}
|
||||
for k, a in fields
|
||||
# Also see `enable_filter` where` is_filterable and is_filterable_vals are set
|
||||
self.filter_targets: dict[str, dict] = {
|
||||
str(k): {'serializer': a, **getattr(a, 'is_filterable_vals', {})}
|
||||
for k, a in self.fields.items()
|
||||
if getattr(a, 'is_filterable', None)
|
||||
}
|
||||
|
||||
# Remove filter args from kwargs to avoid issues with super().__init__
|
||||
poped_kwargs = {} # store popped kwargs as a arg might be reused for multiple fields
|
||||
tgs_vals = {}
|
||||
tgs_vals: dict[str, bool] = {}
|
||||
for k, v in self.filter_targets.items():
|
||||
pop_ref = v['name'] or k
|
||||
pop_ref = v['filter_name'] or k
|
||||
val = kwargs.pop(pop_ref, poped_kwargs.get(pop_ref))
|
||||
if val:
|
||||
if val: # Save popped value for reuse
|
||||
poped_kwargs[pop_ref] = val
|
||||
tgs_vals[k] = str2bool(val) if isinstance(val, str) else val
|
||||
tgs_vals[k] = (
|
||||
str2bool(val) if isinstance(val, (str, int, float)) else bool(val)
|
||||
) # Support for various filtering style for backwards compatibility
|
||||
self.filter_target_values = tgs_vals
|
||||
|
||||
# Ensure this mixin is not proadly applied as it is expensive on scale (total CI time increased by 21% when running all coverage tests)
|
||||
if len(self.filter_targets) == 0 and not self.no_filters:
|
||||
raise Exception(
|
||||
'INVE-W999: No filter targets found in fields, remove `PathScopedMixin`'
|
||||
'INVE-I2: No filter targets found in fields, remove `PathScopedMixin`'
|
||||
)
|
||||
|
||||
return kwargs
|
||||
|
||||
def do_filtering(self, *args, **kwargs):
|
||||
def do_filtering(self) -> None:
|
||||
"""Do the actual filtering."""
|
||||
# This serializer might not contain filters or we do not want to pop fields while generating the schema
|
||||
if (
|
||||
not hasattr(self, 'filter_target_values')
|
||||
or InvenTree.ready.isGeneratingSchema()
|
||||
):
|
||||
return
|
||||
|
||||
# Throw out fields which are not requested
|
||||
# Throw out fields which are not requested (either by default or explicitly)
|
||||
for k, v in self.filter_target_values.items():
|
||||
value = v if v is not None else self.filter_targets[k]['default']
|
||||
# See `enable_filter` where` is_filterable and is_filterable_vals are set
|
||||
value = v if v is not None else bool(self.filter_targets[k]['default'])
|
||||
if value is not True:
|
||||
self.fields.pop(k, None)
|
||||
|
||||
|
||||
# Decorator for marking serialzier fields that can be filtered out
|
||||
def can_filter(func, default=False, name: Optional[str] = None):
|
||||
"""Decorator for marking serializer fields as filterable."""
|
||||
# Ensure this function can be actually filteres
|
||||
if not issubclass(func.__class__, OptFilter):
|
||||
raise TypeError(
|
||||
'INVE-W999: `can_filter` can only be applied to serializers that contain `OptFilter` mixin!'
|
||||
)
|
||||
|
||||
# Mark the function as filterable
|
||||
func._kwargs['is_filterable'] = True
|
||||
func._kwargs['is_filterable_vals'] = {
|
||||
'default': default,
|
||||
'name': name if name else func.field_name,
|
||||
}
|
||||
return func
|
||||
|
||||
|
||||
class FilterableListSerializer(OptFilter, PathScopedMixin, serializers.ListSerializer):
|
||||
# special serializers which allow filtering
|
||||
class FilterableListSerializer(
|
||||
FilterableSerializerField, FilterableSerializerMixin, serializers.ListSerializer
|
||||
):
|
||||
"""Custom ListSerializer which allows filtering of fields."""
|
||||
|
||||
|
||||
class CfListField(OptFilter, serializers.ListField):
|
||||
# special serializer fields which allow filtering
|
||||
class FilterableListField(FilterableSerializerField, serializers.ListField):
|
||||
"""Custom ListField which allows filtering."""
|
||||
|
||||
|
||||
class CfSerializerMethodField(OptFilter, serializers.SerializerMethodField):
|
||||
class FilterableSerializerMethodField(
|
||||
FilterableSerializerField, serializers.SerializerMethodField
|
||||
):
|
||||
"""Custom SerializerMethodField which allows filtering."""
|
||||
|
||||
|
||||
class CfDateTimeField(OptFilter, serializers.DateTimeField):
|
||||
class FilterableDateTimeField(FilterableSerializerField, serializers.DateTimeField):
|
||||
"""Custom DateTimeField which allows filtering."""
|
||||
|
||||
|
||||
class CfFloatField(OptFilter, serializers.FloatField):
|
||||
class FilterableFloatField(FilterableSerializerField, serializers.FloatField):
|
||||
"""Custom FloatField which allows filtering."""
|
||||
|
||||
|
||||
class CfCharField(OptFilter, serializers.CharField):
|
||||
class FilterableCharField(FilterableSerializerField, serializers.CharField):
|
||||
"""Custom CharField which allows filtering."""
|
||||
|
||||
|
||||
class CfIntegerField(OptFilter, serializers.IntegerField):
|
||||
class FilterableIntegerField(FilterableSerializerField, serializers.IntegerField):
|
||||
"""Custom IntegerField which allows filtering."""
|
||||
|
||||
|
||||
@@ -163,10 +190,11 @@ class EmptySerializer(serializers.Serializer):
|
||||
"""Empty serializer for use in testing."""
|
||||
|
||||
|
||||
class InvenTreeMoneySerializer(OptFilter, MoneyField):
|
||||
class InvenTreeMoneySerializer(FilterableSerializerField, MoneyField):
|
||||
"""Custom serializer for 'MoneyField', which ensures that passed values are numerically valid.
|
||||
|
||||
Ref: https://github.com/django-money/django-money/blob/master/djmoney/contrib/django_rest_framework/fields.py
|
||||
This field allows filtering.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -519,8 +547,11 @@ class BareInvenTreeModelSerializer(serializers.ModelSerializer):
|
||||
return data
|
||||
|
||||
|
||||
class InvenTreeModelSerializer(OptFilter, BareInvenTreeModelSerializer):
|
||||
"""Inherits the standard Django ModelSerializer class, but also ensures that the underlying model class data are checked on validation."""
|
||||
class InvenTreeModelSerializer(FilterableSerializerField, BareInvenTreeModelSerializer):
|
||||
"""Inherits the standard Django ModelSerializer class, but also ensures that the underlying model class data are checked on validation.
|
||||
|
||||
This field allows filtering.
|
||||
"""
|
||||
|
||||
|
||||
class InvenTreeTaggitSerializer(TaggitSerializer):
|
||||
|
||||
@@ -32,13 +32,13 @@ from common.settings import get_global_setting
|
||||
from generic.states.fields import InvenTreeCustomStatusSerializerMixin
|
||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.serializers import (
|
||||
CfCharField,
|
||||
CfIntegerField,
|
||||
FilterableCharField,
|
||||
FilterableIntegerField,
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeDecimalField,
|
||||
InvenTreeModelSerializer,
|
||||
NotesFieldMixin,
|
||||
PathScopedMixin,
|
||||
can_filter,
|
||||
enable_filter,
|
||||
)
|
||||
from stock.generators import generate_batch_code
|
||||
from stock.models import StockItem, StockLocation
|
||||
@@ -55,7 +55,7 @@ from .status_codes import BuildStatus
|
||||
|
||||
|
||||
class BuildSerializer(
|
||||
PathScopedMixin,
|
||||
FilterableSerializerMixin,
|
||||
NotesFieldMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTreeCustomStatusSerializerMixin,
|
||||
@@ -118,7 +118,7 @@ class BuildSerializer(
|
||||
|
||||
status_text = serializers.CharField(source='get_status_display', read_only=True)
|
||||
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
part_serializers.PartBriefSerializer(source='part', many=False, read_only=True),
|
||||
True,
|
||||
)
|
||||
@@ -131,46 +131,48 @@ class BuildSerializer(
|
||||
|
||||
overdue = serializers.BooleanField(read_only=True, default=False)
|
||||
|
||||
issued_by_detail = can_filter(
|
||||
UserSerializer(source='issued_by', read_only=True), True, name='user_detail'
|
||||
issued_by_detail = enable_filter(
|
||||
UserSerializer(source='issued_by', read_only=True),
|
||||
True,
|
||||
filter_name='user_detail',
|
||||
)
|
||||
|
||||
responsible_detail = can_filter(
|
||||
responsible_detail = enable_filter(
|
||||
OwnerSerializer(source='responsible', read_only=True, allow_null=True),
|
||||
True,
|
||||
name='user_detail',
|
||||
filter_name='user_detail',
|
||||
)
|
||||
|
||||
barcode_hash = serializers.CharField(read_only=True)
|
||||
|
||||
project_code_label = can_filter(
|
||||
CfCharField(
|
||||
project_code_label = enable_filter(
|
||||
FilterableCharField(
|
||||
source='project_code.code',
|
||||
read_only=True,
|
||||
label=_('Project Code Label'),
|
||||
allow_null=True,
|
||||
),
|
||||
True,
|
||||
name='project_code_detail',
|
||||
filter_name='project_code_detail',
|
||||
)
|
||||
|
||||
project_code_detail = can_filter(
|
||||
project_code_detail = enable_filter(
|
||||
ProjectCodeSerializer(
|
||||
source='project_code', many=False, read_only=True, allow_null=True
|
||||
),
|
||||
True,
|
||||
name='project_code_detail',
|
||||
filter_name='project_code_detail',
|
||||
)
|
||||
|
||||
project_code = can_filter(
|
||||
CfIntegerField(
|
||||
project_code = enable_filter(
|
||||
FilterableIntegerField(
|
||||
allow_null=True,
|
||||
required=False,
|
||||
label=_('Project Code'),
|
||||
help_text=_('Project code for this build order'),
|
||||
),
|
||||
True,
|
||||
name='project_code_detail',
|
||||
filter_name='project_code_detail',
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -1157,7 +1159,7 @@ class BuildAutoAllocationSerializer(serializers.Serializer):
|
||||
|
||||
|
||||
class BuildItemSerializer(
|
||||
PathScopedMixin, DataImportExportSerializerMixin, InvenTreeModelSerializer
|
||||
FilterableSerializerMixin, DataImportExportSerializerMixin, InvenTreeModelSerializer
|
||||
):
|
||||
"""Serializes a BuildItem object, which is an allocation of a stock item against a build order."""
|
||||
|
||||
@@ -1228,7 +1230,7 @@ class BuildItemSerializer(
|
||||
)
|
||||
|
||||
# Extra (optional) detail fields
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
part_serializers.PartBriefSerializer(
|
||||
label=_('Part'),
|
||||
source='stock_item.part',
|
||||
@@ -1240,7 +1242,7 @@ class BuildItemSerializer(
|
||||
True,
|
||||
)
|
||||
|
||||
stock_item_detail = can_filter(
|
||||
stock_item_detail = enable_filter(
|
||||
StockItemSerializer(
|
||||
source='stock_item',
|
||||
read_only=True,
|
||||
@@ -1252,14 +1254,14 @@ class BuildItemSerializer(
|
||||
path_detail=False,
|
||||
),
|
||||
True,
|
||||
name='stock_detail',
|
||||
filter_name='stock_detail',
|
||||
)
|
||||
|
||||
location = serializers.PrimaryKeyRelatedField(
|
||||
label=_('Location'), source='stock_item.location', many=False, read_only=True
|
||||
)
|
||||
|
||||
location_detail = can_filter(
|
||||
location_detail = enable_filter(
|
||||
LocationBriefSerializer(
|
||||
label=_('Location'),
|
||||
source='stock_item.location',
|
||||
@@ -1269,7 +1271,7 @@ class BuildItemSerializer(
|
||||
True,
|
||||
)
|
||||
|
||||
build_detail = can_filter(
|
||||
build_detail = enable_filter(
|
||||
BuildSerializer(
|
||||
label=_('Build'),
|
||||
source='build_line.build',
|
||||
@@ -1293,7 +1295,7 @@ class BuildItemSerializer(
|
||||
|
||||
|
||||
class BuildLineSerializer(
|
||||
PathScopedMixin, DataImportExportSerializerMixin, InvenTreeModelSerializer
|
||||
FilterableSerializerMixin, DataImportExportSerializerMixin, InvenTreeModelSerializer
|
||||
):
|
||||
"""Serializer for a BuildItem object."""
|
||||
|
||||
@@ -1369,7 +1371,7 @@ class BuildLineSerializer(
|
||||
read_only=True,
|
||||
)
|
||||
|
||||
allocations = can_filter(
|
||||
allocations = enable_filter(
|
||||
BuildItemSerializer(many=True, read_only=True, build_detail=False), True
|
||||
)
|
||||
|
||||
@@ -1402,7 +1404,7 @@ class BuildLineSerializer(
|
||||
bom_item = serializers.PrimaryKeyRelatedField(label=_('BOM Item'), read_only=True)
|
||||
|
||||
# Foreign key fields
|
||||
bom_item_detail = can_filter(
|
||||
bom_item_detail = enable_filter(
|
||||
part_serializers.BomItemSerializer(
|
||||
label=_('BOM Item'),
|
||||
source='bom_item',
|
||||
@@ -1417,7 +1419,7 @@ class BuildLineSerializer(
|
||||
True,
|
||||
)
|
||||
|
||||
assembly_detail = can_filter(
|
||||
assembly_detail = enable_filter(
|
||||
part_serializers.PartBriefSerializer(
|
||||
label=_('Assembly'),
|
||||
source='bom_item.part',
|
||||
@@ -1429,7 +1431,7 @@ class BuildLineSerializer(
|
||||
True,
|
||||
)
|
||||
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
part_serializers.PartBriefSerializer(
|
||||
label=_('Part'),
|
||||
source='bom_item.sub_part',
|
||||
@@ -1440,7 +1442,7 @@ class BuildLineSerializer(
|
||||
True,
|
||||
)
|
||||
|
||||
build_detail = can_filter(
|
||||
build_detail = enable_filter(
|
||||
BuildSerializer(
|
||||
label=_('Build'),
|
||||
source='build',
|
||||
|
||||
@@ -18,7 +18,8 @@ from importer.registry import register_importer
|
||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.ready import isGeneratingSchema
|
||||
from InvenTree.serializers import (
|
||||
CfCharField,
|
||||
FilterableCharField,
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeCurrencySerializer,
|
||||
InvenTreeDecimalField,
|
||||
InvenTreeImageSerializerField,
|
||||
@@ -26,9 +27,8 @@ from InvenTree.serializers import (
|
||||
InvenTreeMoneySerializer,
|
||||
InvenTreeTagModelSerializer,
|
||||
NotesFieldMixin,
|
||||
PathScopedMixin,
|
||||
RemoteImageMixin,
|
||||
can_filter,
|
||||
enable_filter,
|
||||
)
|
||||
|
||||
from .models import (
|
||||
@@ -251,7 +251,7 @@ class ContactSerializer(DataImportExportSerializerMixin, InvenTreeModelSerialize
|
||||
|
||||
@register_importer()
|
||||
class ManufacturerPartSerializer(
|
||||
PathScopedMixin,
|
||||
FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTreeTagModelSerializer,
|
||||
NotesFieldMixin,
|
||||
@@ -279,22 +279,22 @@ class ManufacturerPartSerializer(
|
||||
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
part_serializers.PartBriefSerializer(
|
||||
source='part', many=False, read_only=True, allow_null=True
|
||||
),
|
||||
True,
|
||||
)
|
||||
|
||||
manufacturer_detail = can_filter(
|
||||
manufacturer_detail = enable_filter(
|
||||
CompanyBriefSerializer(
|
||||
source='manufacturer', many=False, read_only=True, allow_null=True
|
||||
),
|
||||
True,
|
||||
)
|
||||
|
||||
pretty_name = can_filter(
|
||||
CfCharField(read_only=True, allow_null=True), name='pretty'
|
||||
pretty_name = enable_filter(
|
||||
FilterableCharField(read_only=True, allow_null=True), filter_name='pretty'
|
||||
)
|
||||
|
||||
manufacturer = serializers.PrimaryKeyRelatedField(
|
||||
@@ -304,7 +304,7 @@ class ManufacturerPartSerializer(
|
||||
|
||||
@register_importer()
|
||||
class ManufacturerPartParameterSerializer(
|
||||
PathScopedMixin, DataImportExportSerializerMixin, InvenTreeModelSerializer
|
||||
FilterableSerializerMixin, DataImportExportSerializerMixin, InvenTreeModelSerializer
|
||||
):
|
||||
"""Serializer for the ManufacturerPartParameter model."""
|
||||
|
||||
@@ -322,7 +322,7 @@ class ManufacturerPartParameterSerializer(
|
||||
'units',
|
||||
]
|
||||
|
||||
manufacturer_part_detail = can_filter(
|
||||
manufacturer_part_detail = enable_filter(
|
||||
ManufacturerPartSerializer(
|
||||
source='manufacturer_part', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
@@ -331,7 +331,7 @@ class ManufacturerPartParameterSerializer(
|
||||
|
||||
@register_importer()
|
||||
class SupplierPartSerializer(
|
||||
PathScopedMixin,
|
||||
FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTreeTagModelSerializer,
|
||||
NotesFieldMixin,
|
||||
@@ -532,7 +532,7 @@ class SupplierPartSerializer(
|
||||
|
||||
@register_importer()
|
||||
class SupplierPriceBreakSerializer(
|
||||
PathScopedMixin, DataImportExportSerializerMixin, InvenTreeModelSerializer
|
||||
FilterableSerializerMixin, DataImportExportSerializerMixin, InvenTreeModelSerializer
|
||||
):
|
||||
"""Serializer for SupplierPriceBreak object."""
|
||||
|
||||
@@ -569,14 +569,14 @@ class SupplierPriceBreakSerializer(
|
||||
source='part.supplier', many=False, read_only=True
|
||||
)
|
||||
|
||||
supplier_detail = can_filter(
|
||||
supplier_detail = enable_filter(
|
||||
CompanyBriefSerializer(
|
||||
source='part.supplier', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
)
|
||||
|
||||
# Detail serializer for SupplierPart
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
SupplierPartSerializer(
|
||||
source='part', brief=True, many=False, read_only=True, allow_null=True
|
||||
)
|
||||
|
||||
@@ -45,13 +45,13 @@ from InvenTree.helpers import (
|
||||
)
|
||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.serializers import (
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeCurrencySerializer,
|
||||
InvenTreeDecimalField,
|
||||
InvenTreeModelSerializer,
|
||||
InvenTreeMoneySerializer,
|
||||
NotesFieldMixin,
|
||||
PathScopedMixin,
|
||||
can_filter,
|
||||
enable_filter,
|
||||
)
|
||||
from order.status_codes import (
|
||||
PurchaseOrderStatusGroups,
|
||||
@@ -303,7 +303,7 @@ class AbstractExtraLineMeta:
|
||||
|
||||
@register_importer()
|
||||
class PurchaseOrderSerializer(
|
||||
PathScopedMixin,
|
||||
FilterableSerializerMixin,
|
||||
NotesFieldMixin,
|
||||
TotalPriceMixin,
|
||||
InvenTreeCustomStatusSerializerMixin,
|
||||
@@ -369,7 +369,7 @@ class PurchaseOrderSerializer(
|
||||
source='supplier.name', read_only=True, label=_('Supplier Name')
|
||||
)
|
||||
|
||||
supplier_detail = can_filter(
|
||||
supplier_detail = enable_filter(
|
||||
CompanyBriefSerializer(
|
||||
source='supplier', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
@@ -460,7 +460,7 @@ class PurchaseOrderIssueSerializer(OrderAdjustSerializer):
|
||||
|
||||
@register_importer()
|
||||
class PurchaseOrderLineItemSerializer(
|
||||
PathScopedMixin,
|
||||
FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
AbstractLineItemSerializer,
|
||||
InvenTreeModelSerializer,
|
||||
@@ -583,18 +583,18 @@ class PurchaseOrderLineItemSerializer(
|
||||
|
||||
total_price = serializers.FloatField(read_only=True)
|
||||
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
PartBriefSerializer(
|
||||
source='get_base_part', many=False, read_only=True, allow_null=True
|
||||
),
|
||||
name='part_detail',
|
||||
filter_name='part_detail',
|
||||
)
|
||||
|
||||
supplier_part_detail = can_filter(
|
||||
supplier_part_detail = enable_filter(
|
||||
SupplierPartSerializer(
|
||||
source='part', brief=True, many=False, read_only=True, allow_null=True
|
||||
),
|
||||
name='part_detail',
|
||||
filter_name='part_detail',
|
||||
)
|
||||
|
||||
purchase_price = InvenTreeMoneySerializer(allow_null=True)
|
||||
@@ -615,7 +615,7 @@ class PurchaseOrderLineItemSerializer(
|
||||
help_text=_('Purchase price currency')
|
||||
)
|
||||
|
||||
order_detail = can_filter(
|
||||
order_detail = enable_filter(
|
||||
PurchaseOrderSerializer(
|
||||
source='order', read_only=True, allow_null=True, many=False
|
||||
)
|
||||
@@ -693,11 +693,11 @@ class PurchaseOrderLineItemSerializer(
|
||||
|
||||
@register_importer()
|
||||
class PurchaseOrderExtraLineSerializer(
|
||||
PathScopedMixin, AbstractExtraLineSerializer, InvenTreeModelSerializer
|
||||
FilterableSerializerMixin, AbstractExtraLineSerializer, InvenTreeModelSerializer
|
||||
):
|
||||
"""Serializer for a PurchaseOrderExtraLine object."""
|
||||
|
||||
order_detail = can_filter(
|
||||
order_detail = enable_filter(
|
||||
PurchaseOrderSerializer(
|
||||
source='order', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
@@ -956,7 +956,7 @@ class PurchaseOrderReceiveSerializer(serializers.Serializer):
|
||||
|
||||
@register_importer()
|
||||
class SalesOrderSerializer(
|
||||
PathScopedMixin,
|
||||
FilterableSerializerMixin,
|
||||
NotesFieldMixin,
|
||||
TotalPriceMixin,
|
||||
InvenTreeCustomStatusSerializerMixin,
|
||||
@@ -1022,7 +1022,7 @@ class SalesOrderSerializer(
|
||||
|
||||
return queryset
|
||||
|
||||
customer_detail = can_filter(
|
||||
customer_detail = enable_filter(
|
||||
CompanyBriefSerializer(
|
||||
source='customer', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
@@ -1047,7 +1047,7 @@ class SalesOrderIssueSerializer(OrderAdjustSerializer):
|
||||
|
||||
@register_importer()
|
||||
class SalesOrderLineItemSerializer(
|
||||
PathScopedMixin,
|
||||
FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
AbstractLineItemSerializer,
|
||||
InvenTreeModelSerializer,
|
||||
@@ -1179,15 +1179,15 @@ class SalesOrderLineItemSerializer(
|
||||
|
||||
return queryset
|
||||
|
||||
order_detail = can_filter(
|
||||
order_detail = enable_filter(
|
||||
SalesOrderSerializer(
|
||||
source='order', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
)
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
PartBriefSerializer(source='part', many=False, read_only=True, allow_null=True)
|
||||
)
|
||||
customer_detail = can_filter(
|
||||
customer_detail = enable_filter(
|
||||
CompanyBriefSerializer(
|
||||
source='order.customer', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
@@ -1215,7 +1215,7 @@ class SalesOrderLineItemSerializer(
|
||||
|
||||
@register_importer()
|
||||
class SalesOrderShipmentSerializer(
|
||||
PathScopedMixin, NotesFieldMixin, InvenTreeModelSerializer
|
||||
FilterableSerializerMixin, NotesFieldMixin, InvenTreeModelSerializer
|
||||
):
|
||||
"""Serializer for the SalesOrderShipment class."""
|
||||
|
||||
@@ -1253,7 +1253,7 @@ class SalesOrderShipmentSerializer(
|
||||
read_only=True, allow_null=True, label=_('Allocated Items')
|
||||
)
|
||||
|
||||
order_detail = can_filter(
|
||||
order_detail = enable_filter(
|
||||
SalesOrderSerializer(
|
||||
source='order', read_only=True, allow_null=True, many=False
|
||||
),
|
||||
@@ -1261,7 +1261,9 @@ class SalesOrderShipmentSerializer(
|
||||
)
|
||||
|
||||
|
||||
class SalesOrderAllocationSerializer(PathScopedMixin, InvenTreeModelSerializer):
|
||||
class SalesOrderAllocationSerializer(
|
||||
FilterableSerializerMixin, InvenTreeModelSerializer
|
||||
):
|
||||
"""Serializer for the SalesOrderAllocation model.
|
||||
|
||||
This includes some fields from the related model objects.
|
||||
@@ -1303,18 +1305,18 @@ class SalesOrderAllocationSerializer(PathScopedMixin, InvenTreeModelSerializer):
|
||||
)
|
||||
|
||||
# Extra detail fields
|
||||
order_detail = can_filter(
|
||||
order_detail = enable_filter(
|
||||
SalesOrderSerializer(
|
||||
source='line.order', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
)
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
PartBriefSerializer(
|
||||
source='item.part', many=False, read_only=True, allow_null=True
|
||||
),
|
||||
True,
|
||||
)
|
||||
item_detail = can_filter(
|
||||
item_detail = enable_filter(
|
||||
stock.serializers.StockItemSerializer(
|
||||
source='item',
|
||||
many=False,
|
||||
@@ -1326,12 +1328,12 @@ class SalesOrderAllocationSerializer(PathScopedMixin, InvenTreeModelSerializer):
|
||||
),
|
||||
True,
|
||||
)
|
||||
location_detail = can_filter(
|
||||
location_detail = enable_filter(
|
||||
stock.serializers.LocationBriefSerializer(
|
||||
source='item.location', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
)
|
||||
customer_detail = can_filter(
|
||||
customer_detail = enable_filter(
|
||||
CompanyBriefSerializer(
|
||||
source='line.order.customer', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
@@ -1775,7 +1777,7 @@ class SalesOrderShipmentAllocationSerializer(serializers.Serializer):
|
||||
|
||||
@register_importer()
|
||||
class SalesOrderExtraLineSerializer(
|
||||
PathScopedMixin, AbstractExtraLineSerializer, InvenTreeModelSerializer
|
||||
FilterableSerializerMixin, AbstractExtraLineSerializer, InvenTreeModelSerializer
|
||||
):
|
||||
"""Serializer for a SalesOrderExtraLine object."""
|
||||
|
||||
@@ -1784,7 +1786,7 @@ class SalesOrderExtraLineSerializer(
|
||||
|
||||
model = order.models.SalesOrderExtraLine
|
||||
|
||||
order_detail = can_filter(
|
||||
order_detail = enable_filter(
|
||||
SalesOrderSerializer(
|
||||
source='order', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
@@ -1793,7 +1795,7 @@ class SalesOrderExtraLineSerializer(
|
||||
|
||||
@register_importer()
|
||||
class ReturnOrderSerializer(
|
||||
PathScopedMixin,
|
||||
FilterableSerializerMixin,
|
||||
NotesFieldMixin,
|
||||
InvenTreeCustomStatusSerializerMixin,
|
||||
AbstractOrderSerializer,
|
||||
@@ -1845,7 +1847,7 @@ class ReturnOrderSerializer(
|
||||
|
||||
return queryset
|
||||
|
||||
customer_detail = can_filter(
|
||||
customer_detail = enable_filter(
|
||||
CompanyBriefSerializer(
|
||||
source='customer', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
@@ -1984,7 +1986,7 @@ class ReturnOrderReceiveSerializer(serializers.Serializer):
|
||||
|
||||
@register_importer()
|
||||
class ReturnOrderLineItemSerializer(
|
||||
PathScopedMixin,
|
||||
FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
AbstractLineItemSerializer,
|
||||
InvenTreeModelSerializer,
|
||||
@@ -2014,7 +2016,7 @@ class ReturnOrderLineItemSerializer(
|
||||
'link',
|
||||
]
|
||||
|
||||
order_detail = can_filter(
|
||||
order_detail = enable_filter(
|
||||
ReturnOrderSerializer(
|
||||
source='order', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
@@ -2024,13 +2026,13 @@ class ReturnOrderLineItemSerializer(
|
||||
label=_('Quantity'), help_text=_('Quantity to return')
|
||||
)
|
||||
|
||||
item_detail = can_filter(
|
||||
item_detail = enable_filter(
|
||||
stock.serializers.StockItemSerializer(
|
||||
source='item', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
)
|
||||
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
PartBriefSerializer(
|
||||
source='item.part', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
@@ -2042,7 +2044,7 @@ class ReturnOrderLineItemSerializer(
|
||||
|
||||
@register_importer()
|
||||
class ReturnOrderExtraLineSerializer(
|
||||
PathScopedMixin, AbstractExtraLineSerializer, InvenTreeModelSerializer
|
||||
FilterableSerializerMixin, AbstractExtraLineSerializer, InvenTreeModelSerializer
|
||||
):
|
||||
"""Serializer for a ReturnOrderExtraLine object."""
|
||||
|
||||
@@ -2051,7 +2053,7 @@ class ReturnOrderExtraLineSerializer(
|
||||
|
||||
model = order.models.ReturnOrderExtraLine
|
||||
|
||||
order_detail = can_filter(
|
||||
order_detail = enable_filter(
|
||||
ReturnOrderSerializer(
|
||||
source='order', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
|
||||
@@ -33,11 +33,11 @@ from importer.registry import register_importer
|
||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.ready import isGeneratingSchema
|
||||
from InvenTree.serializers import (
|
||||
CfDateTimeField,
|
||||
CfFloatField,
|
||||
CfListField,
|
||||
FilterableDateTimeField,
|
||||
FilterableFloatField,
|
||||
FilterableListField,
|
||||
FilterableListSerializer,
|
||||
can_filter,
|
||||
enable_filter,
|
||||
)
|
||||
from users.serializers import UserSerializer
|
||||
|
||||
@@ -63,7 +63,7 @@ logger = structlog.get_logger('inventree')
|
||||
|
||||
@register_importer()
|
||||
class CategorySerializer(
|
||||
InvenTree.serializers.PathScopedMixin,
|
||||
InvenTree.serializers.FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTree.serializers.InvenTreeModelSerializer,
|
||||
):
|
||||
@@ -131,14 +131,14 @@ class CategorySerializer(
|
||||
"""Return True if the category is directly "starred" by the current user."""
|
||||
return category in self.context.get('starred_categories', [])
|
||||
|
||||
path = can_filter(
|
||||
CfListField(
|
||||
path = enable_filter(
|
||||
FilterableListField(
|
||||
child=serializers.DictField(),
|
||||
source='get_path',
|
||||
read_only=True,
|
||||
allow_null=True,
|
||||
),
|
||||
name='path_detail',
|
||||
filter_name='path_detail',
|
||||
)
|
||||
|
||||
icon = serializers.CharField(
|
||||
@@ -314,7 +314,7 @@ class PartParameterTemplateSerializer(
|
||||
|
||||
|
||||
class PartBriefSerializer(
|
||||
InvenTree.serializers.PathScopedMixin,
|
||||
InvenTree.serializers.FilterableSerializerMixin,
|
||||
InvenTree.serializers.InvenTreeModelSerializer,
|
||||
):
|
||||
"""Serializer for Part (brief detail)."""
|
||||
@@ -374,25 +374,25 @@ class PartBriefSerializer(
|
||||
)
|
||||
|
||||
# Pricing fields
|
||||
pricing_min = can_filter(
|
||||
pricing_min = enable_filter(
|
||||
InvenTree.serializers.InvenTreeMoneySerializer(
|
||||
source='pricing_data.overall_min', allow_null=True, read_only=True
|
||||
),
|
||||
True,
|
||||
name='pricing',
|
||||
filter_name='pricing',
|
||||
)
|
||||
pricing_max = can_filter(
|
||||
pricing_max = enable_filter(
|
||||
InvenTree.serializers.InvenTreeMoneySerializer(
|
||||
source='pricing_data.overall_max', allow_null=True, read_only=True
|
||||
),
|
||||
True,
|
||||
name='pricing',
|
||||
filter_name='pricing',
|
||||
)
|
||||
|
||||
|
||||
@register_importer()
|
||||
class PartParameterSerializer(
|
||||
InvenTree.serializers.PathScopedMixin,
|
||||
InvenTree.serializers.FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTree.serializers.InvenTreeModelSerializer,
|
||||
):
|
||||
@@ -428,11 +428,11 @@ class PartParameterSerializer(
|
||||
|
||||
return instance
|
||||
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
PartBriefSerializer(source='part', many=False, read_only=True, allow_null=True)
|
||||
)
|
||||
|
||||
template_detail = can_filter(
|
||||
template_detail = enable_filter(
|
||||
PartParameterTemplateSerializer(
|
||||
source='template', many=False, read_only=True, allow_null=True
|
||||
),
|
||||
@@ -627,7 +627,7 @@ class DefaultLocationSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
||||
|
||||
@register_importer()
|
||||
class PartSerializer(
|
||||
InvenTree.serializers.PathScopedMixin,
|
||||
InvenTree.serializers.FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTree.serializers.NotesFieldMixin,
|
||||
InvenTree.serializers.RemoteImageMixin,
|
||||
@@ -878,27 +878,27 @@ class PartSerializer(
|
||||
return part in self.starred_parts
|
||||
|
||||
# Extra detail for the category
|
||||
category_detail = can_filter(
|
||||
category_detail = enable_filter(
|
||||
CategorySerializer(
|
||||
source='category', many=False, read_only=True, allow_null=True
|
||||
)
|
||||
)
|
||||
|
||||
category_path = can_filter(
|
||||
CfListField(
|
||||
category_path = enable_filter(
|
||||
FilterableListField(
|
||||
child=serializers.DictField(),
|
||||
source='category.get_path',
|
||||
read_only=True,
|
||||
allow_null=True,
|
||||
),
|
||||
name='path_detail',
|
||||
filter_name='path_detail',
|
||||
)
|
||||
|
||||
default_location_detail = can_filter(
|
||||
default_location_detail = enable_filter(
|
||||
DefaultLocationSerializer(
|
||||
source='default_location', many=False, read_only=True, allow_null=True
|
||||
),
|
||||
name='location_detail',
|
||||
filter_name='location_detail',
|
||||
)
|
||||
|
||||
category_name = serializers.CharField(
|
||||
@@ -1006,27 +1006,29 @@ class PartSerializer(
|
||||
)
|
||||
|
||||
# Pricing fields
|
||||
pricing_min = can_filter(
|
||||
pricing_min = enable_filter(
|
||||
InvenTree.serializers.InvenTreeMoneySerializer(
|
||||
source='pricing_data.overall_min', allow_null=True, read_only=True
|
||||
),
|
||||
True,
|
||||
name='pricing',
|
||||
filter_name='pricing',
|
||||
)
|
||||
pricing_max = can_filter(
|
||||
pricing_max = enable_filter(
|
||||
InvenTree.serializers.InvenTreeMoneySerializer(
|
||||
source='pricing_data.overall_max', allow_null=True, read_only=True
|
||||
),
|
||||
True,
|
||||
name='pricing',
|
||||
filter_name='pricing',
|
||||
)
|
||||
pricing_updated = can_filter(
|
||||
CfDateTimeField(source='pricing_data.updated', allow_null=True, read_only=True),
|
||||
pricing_updated = enable_filter(
|
||||
FilterableDateTimeField(
|
||||
source='pricing_data.updated', allow_null=True, read_only=True
|
||||
),
|
||||
True,
|
||||
name='pricing',
|
||||
filter_name='pricing',
|
||||
)
|
||||
|
||||
parameters = can_filter(
|
||||
parameters = enable_filter(
|
||||
PartParameterSerializer(many=True, read_only=True, allow_null=True)
|
||||
)
|
||||
|
||||
@@ -1615,7 +1617,7 @@ class BomItemSubstituteSerializer(InvenTree.serializers.InvenTreeModelSerializer
|
||||
|
||||
@register_importer()
|
||||
class BomItemSerializer(
|
||||
InvenTree.serializers.PathScopedMixin,
|
||||
InvenTree.serializers.FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTree.serializers.InvenTreeModelSerializer,
|
||||
):
|
||||
@@ -1694,11 +1696,11 @@ class BomItemSerializer(
|
||||
help_text=_('Select the parent assembly'),
|
||||
)
|
||||
|
||||
substitutes = can_filter(
|
||||
substitutes = enable_filter(
|
||||
BomItemSubstituteSerializer(many=True, read_only=True, allow_null=True), True
|
||||
)
|
||||
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
PartBriefSerializer(
|
||||
source='part',
|
||||
label=_('Assembly'),
|
||||
@@ -1714,7 +1716,7 @@ class BomItemSerializer(
|
||||
help_text=_('Select the component part'),
|
||||
)
|
||||
|
||||
sub_part_detail = can_filter(
|
||||
sub_part_detail = enable_filter(
|
||||
PartBriefSerializer(
|
||||
source='sub_part',
|
||||
label=_('Component'),
|
||||
@@ -1733,41 +1735,42 @@ class BomItemSerializer(
|
||||
label=_('In Production'), read_only=True, allow_null=True
|
||||
)
|
||||
|
||||
can_build = can_filter(
|
||||
CfFloatField(label=_('Can Build'), read_only=True, allow_null=True), True
|
||||
can_build = enable_filter(
|
||||
FilterableFloatField(label=_('Can Build'), read_only=True, allow_null=True),
|
||||
True,
|
||||
)
|
||||
|
||||
# Cached pricing fields
|
||||
pricing_min = can_filter(
|
||||
pricing_min = enable_filter(
|
||||
InvenTree.serializers.InvenTreeMoneySerializer(
|
||||
source='sub_part.pricing_data.overall_min', allow_null=True, read_only=True
|
||||
),
|
||||
True,
|
||||
name='pricing',
|
||||
filter_name='pricing',
|
||||
)
|
||||
pricing_max = can_filter(
|
||||
pricing_max = enable_filter(
|
||||
InvenTree.serializers.InvenTreeMoneySerializer(
|
||||
source='sub_part.pricing_data.overall_max', allow_null=True, read_only=True
|
||||
),
|
||||
True,
|
||||
name='pricing',
|
||||
filter_name='pricing',
|
||||
)
|
||||
pricing_min_total = can_filter(
|
||||
pricing_min_total = enable_filter(
|
||||
InvenTree.serializers.InvenTreeMoneySerializer(allow_null=True, read_only=True),
|
||||
True,
|
||||
name='pricing',
|
||||
filter_name='pricing',
|
||||
)
|
||||
pricing_max_total = can_filter(
|
||||
pricing_max_total = enable_filter(
|
||||
InvenTree.serializers.InvenTreeMoneySerializer(allow_null=True, read_only=True),
|
||||
True,
|
||||
name='pricing',
|
||||
filter_name='pricing',
|
||||
)
|
||||
pricing_updated = can_filter(
|
||||
CfDateTimeField(
|
||||
pricing_updated = enable_filter(
|
||||
FilterableDateTimeField(
|
||||
source='sub_part.pricing_data.updated', allow_null=True, read_only=True
|
||||
),
|
||||
True,
|
||||
name='pricing',
|
||||
filter_name='pricing',
|
||||
)
|
||||
|
||||
# Annotated fields for available stock
|
||||
|
||||
@@ -33,10 +33,10 @@ from generic.states.fields import InvenTreeCustomStatusSerializerMixin
|
||||
from importer.registry import register_importer
|
||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.serializers import (
|
||||
CfListField,
|
||||
FilterableListField,
|
||||
InvenTreeCurrencySerializer,
|
||||
InvenTreeDecimalField,
|
||||
can_filter,
|
||||
enable_filter,
|
||||
)
|
||||
from users.serializers import UserSerializer
|
||||
|
||||
@@ -194,7 +194,7 @@ class LocationBriefSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
||||
|
||||
@register_importer()
|
||||
class StockItemTestResultSerializer(
|
||||
InvenTree.serializers.PathScopedMixin,
|
||||
InvenTree.serializers.FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTree.serializers.InvenTreeModelSerializer,
|
||||
):
|
||||
@@ -222,7 +222,7 @@ class StockItemTestResultSerializer(
|
||||
]
|
||||
read_only_fields = ['pk', 'user', 'date']
|
||||
|
||||
user_detail = can_filter(
|
||||
user_detail = enable_filter(
|
||||
UserSerializer(source='user', read_only=True, allow_null=True)
|
||||
)
|
||||
|
||||
@@ -235,7 +235,7 @@ class StockItemTestResultSerializer(
|
||||
label=_('Test template for this result'),
|
||||
)
|
||||
|
||||
template_detail = can_filter(
|
||||
template_detail = enable_filter(
|
||||
part_serializers.PartTestTemplateSerializer(
|
||||
source='template', read_only=True, allow_null=True
|
||||
)
|
||||
@@ -297,7 +297,7 @@ class StockItemTestResultSerializer(
|
||||
|
||||
@register_importer()
|
||||
class StockItemSerializer(
|
||||
InvenTree.serializers.PathScopedMixin,
|
||||
InvenTree.serializers.FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTreeCustomStatusSerializerMixin,
|
||||
InvenTree.serializers.InvenTreeTagModelSerializer,
|
||||
@@ -415,14 +415,14 @@ class StockItemSerializer(
|
||||
help_text=_('Parent stock item'),
|
||||
)
|
||||
|
||||
location_path = can_filter(
|
||||
CfListField(
|
||||
location_path = enable_filter(
|
||||
FilterableListField(
|
||||
child=serializers.DictField(),
|
||||
source='location.get_path',
|
||||
read_only=True,
|
||||
allow_null=True,
|
||||
),
|
||||
name='path_detail',
|
||||
filter_name='path_detail',
|
||||
)
|
||||
|
||||
in_stock = serializers.BooleanField(read_only=True, label=_('In Stock'))
|
||||
@@ -574,7 +574,7 @@ class StockItemSerializer(
|
||||
)
|
||||
|
||||
# Optional detail fields, which can be appended via query parameters
|
||||
supplier_part_detail = can_filter(
|
||||
supplier_part_detail = enable_filter(
|
||||
company_serializers.SupplierPartSerializer(
|
||||
label=_('Supplier Part'),
|
||||
source='supplier_part',
|
||||
@@ -589,14 +589,14 @@ class StockItemSerializer(
|
||||
True,
|
||||
)
|
||||
|
||||
part_detail = can_filter(
|
||||
part_detail = enable_filter(
|
||||
part_serializers.PartBriefSerializer(
|
||||
label=_('Part'), source='part', many=False, read_only=True, allow_null=True
|
||||
),
|
||||
True,
|
||||
)
|
||||
|
||||
location_detail = can_filter(
|
||||
location_detail = enable_filter(
|
||||
LocationBriefSerializer(
|
||||
label=_('Location'),
|
||||
source='location',
|
||||
@@ -607,7 +607,7 @@ class StockItemSerializer(
|
||||
True,
|
||||
)
|
||||
|
||||
tests = can_filter(
|
||||
tests = enable_filter(
|
||||
StockItemTestResultSerializer(
|
||||
source='test_results', many=True, read_only=True, allow_null=True
|
||||
)
|
||||
@@ -1122,7 +1122,7 @@ class LocationTreeSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
||||
|
||||
@register_importer()
|
||||
class LocationSerializer(
|
||||
InvenTree.serializers.PathScopedMixin,
|
||||
InvenTree.serializers.FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTree.serializers.InvenTreeTagModelSerializer,
|
||||
):
|
||||
@@ -1187,14 +1187,14 @@ class LocationSerializer(
|
||||
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
path = can_filter(
|
||||
CfListField(
|
||||
path = enable_filter(
|
||||
FilterableListField(
|
||||
child=serializers.DictField(),
|
||||
source='get_path',
|
||||
read_only=True,
|
||||
allow_null=True,
|
||||
),
|
||||
name='path_detail',
|
||||
filter_name='path_detail',
|
||||
)
|
||||
|
||||
# explicitly set this field, so it gets included for AutoSchema
|
||||
@@ -1208,7 +1208,7 @@ class LocationSerializer(
|
||||
|
||||
@register_importer()
|
||||
class StockTrackingSerializer(
|
||||
InvenTree.serializers.PathScopedMixin,
|
||||
InvenTree.serializers.FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTree.serializers.InvenTreeModelSerializer,
|
||||
):
|
||||
@@ -1234,11 +1234,11 @@ class StockTrackingSerializer(
|
||||
|
||||
label = serializers.CharField(read_only=True)
|
||||
|
||||
item_detail = can_filter(
|
||||
item_detail = enable_filter(
|
||||
StockItemSerializer(source='item', many=False, read_only=True, allow_null=True)
|
||||
)
|
||||
|
||||
user_detail = can_filter(
|
||||
user_detail = enable_filter(
|
||||
UserSerializer(source='user', many=False, read_only=True, allow_null=True)
|
||||
)
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ from rest_framework import serializers
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
|
||||
from InvenTree.serializers import (
|
||||
CfSerializerMethodField,
|
||||
FilterableListSerializer,
|
||||
FilterableSerializerMethodField,
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeModelSerializer,
|
||||
PathScopedMixin,
|
||||
can_filter,
|
||||
enable_filter,
|
||||
)
|
||||
|
||||
from .models import ApiToken, Owner, RuleSet, UserProfile
|
||||
@@ -239,7 +239,7 @@ class ApiTokenSerializer(InvenTreeModelSerializer):
|
||||
user_detail = UserSerializer(source='user', read_only=True)
|
||||
|
||||
|
||||
class GroupSerializer(PathScopedMixin, InvenTreeModelSerializer):
|
||||
class GroupSerializer(FilterableSerializerMixin, InvenTreeModelSerializer):
|
||||
"""Serializer for a 'Group'."""
|
||||
|
||||
class Meta:
|
||||
@@ -248,25 +248,25 @@ class GroupSerializer(PathScopedMixin, InvenTreeModelSerializer):
|
||||
model = Group
|
||||
fields = ['pk', 'name', 'permissions', 'roles', 'users']
|
||||
|
||||
permissions = can_filter(
|
||||
CfSerializerMethodField(allow_null=True, read_only=True),
|
||||
name='permission_detail',
|
||||
permissions = enable_filter(
|
||||
FilterableSerializerMethodField(allow_null=True, read_only=True),
|
||||
filter_name='permission_detail',
|
||||
)
|
||||
|
||||
def get_permissions(self, group: Group) -> dict:
|
||||
"""Return a list of permissions associated with the group."""
|
||||
return generate_permission_dict(group.permissions.all())
|
||||
|
||||
roles = can_filter(
|
||||
roles = enable_filter(
|
||||
RuleSetSerializer(
|
||||
source='rule_sets', many=True, read_only=True, allow_null=True
|
||||
),
|
||||
name='role_detail',
|
||||
filter_name='role_detail',
|
||||
)
|
||||
|
||||
users = can_filter(
|
||||
users = enable_filter(
|
||||
UserSerializer(source='user_set', many=True, read_only=True, allow_null=True),
|
||||
name='user_detail',
|
||||
filter_name='user_detail',
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user