mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-28 03:26:45 +00:00
Schema: (Redo) Remove hardcoded enum values from customizable fields (#9452)
* Remove hardcoded currency enum from schema * Convert schema custom key enums to int to allow customized keys to validate * Convert stock status key enums to int to allow customizations to validate in schema * api version bump * Restore enumerated help text for currencies * Remove commented block of old code * Restore custom key enumerated values to schema documentation * Restore status key enumeration to schema documentation
This commit is contained in:
parent
f541d76cd1
commit
f87f4387ed
@ -1,12 +1,16 @@
|
|||||||
"""InvenTree API version information."""
|
"""InvenTree API version information."""
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 332
|
INVENTREE_API_VERSION = 333
|
||||||
|
|
||||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||||
|
|
||||||
|
|
||||||
INVENTREE_API_TEXT = """
|
INVENTREE_API_TEXT = """
|
||||||
|
v333 - 2025-04-03 : https://github.com/inventree/InvenTree/pull/9452
|
||||||
|
- Currency string is no longer restricted to a hardcoded enum
|
||||||
|
- Customizable status keys are no longer hardcoded enum values
|
||||||
|
|
||||||
v332 - 2025-04-02 : https://github.com/inventree/InvenTree/pull/9393
|
v332 - 2025-04-02 : https://github.com/inventree/InvenTree/pull/9393
|
||||||
- Adds 'search_notes' parameter to all searchable API endpoints
|
- Adds 'search_notes' parameter to all searchable API endpoints
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from djmoney.contrib.django_rest_framework.fields import MoneyField
|
from djmoney.contrib.django_rest_framework.fields import MoneyField
|
||||||
from djmoney.money import Money
|
from djmoney.money import Money
|
||||||
from djmoney.utils import MONEY_CLASSES, get_currency_field_name
|
from djmoney.utils import MONEY_CLASSES, get_currency_field_name
|
||||||
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
from rest_framework.fields import empty
|
from rest_framework.fields import empty
|
||||||
@ -86,6 +87,7 @@ class InvenTreeMoneySerializer(MoneyField):
|
|||||||
return amount
|
return amount
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema_field(serializers.CharField())
|
||||||
class InvenTreeCurrencySerializer(serializers.ChoiceField):
|
class InvenTreeCurrencySerializer(serializers.ChoiceField):
|
||||||
"""Custom serializers for selecting currency option."""
|
"""Custom serializers for selecting currency option."""
|
||||||
|
|
||||||
@ -111,6 +113,14 @@ class InvenTreeCurrencySerializer(serializers.ChoiceField):
|
|||||||
if 'help_text' not in kwargs:
|
if 'help_text' not in kwargs:
|
||||||
kwargs['help_text'] = _('Select currency from available options')
|
kwargs['help_text'] = _('Select currency from available options')
|
||||||
|
|
||||||
|
if InvenTree.ready.isGeneratingSchema():
|
||||||
|
kwargs['help_text'] = (
|
||||||
|
kwargs['help_text']
|
||||||
|
+ '\n\n'
|
||||||
|
+ '\n'.join(f'* `{value}` - {label}' for value, label in choices)
|
||||||
|
+ "\n\nOther valid currencies may be found in the 'CURRENCY_CODES' global setting."
|
||||||
|
)
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +40,11 @@ from InvenTree.serializers import (
|
|||||||
)
|
)
|
||||||
from stock.generators import generate_batch_code
|
from stock.generators import generate_batch_code
|
||||||
from stock.models import StockItem, StockLocation
|
from stock.models import StockItem, StockLocation
|
||||||
from stock.serializers import LocationBriefSerializer, StockItemSerializerBrief
|
from stock.serializers import (
|
||||||
|
LocationBriefSerializer,
|
||||||
|
StockItemSerializerBrief,
|
||||||
|
StockStatusCustomSerializer,
|
||||||
|
)
|
||||||
from stock.status_codes import StockStatus
|
from stock.status_codes import StockStatus
|
||||||
from users.serializers import OwnerSerializer, UserSerializer
|
from users.serializers import OwnerSerializer, UserSerializer
|
||||||
|
|
||||||
@ -581,11 +585,7 @@ class BuildOutputCompleteSerializer(serializers.Serializer):
|
|||||||
help_text=_('Location for completed build outputs'),
|
help_text=_('Location for completed build outputs'),
|
||||||
)
|
)
|
||||||
|
|
||||||
status_custom_key = serializers.ChoiceField(
|
status_custom_key = StockStatusCustomSerializer(default=StockStatus.OK.value)
|
||||||
choices=StockStatus.items(custom=True),
|
|
||||||
default=StockStatus.OK.value,
|
|
||||||
label=_('Status'),
|
|
||||||
)
|
|
||||||
|
|
||||||
accept_incomplete_allocation = serializers.BooleanField(
|
accept_incomplete_allocation = serializers.BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
|
@ -8,9 +8,13 @@ from django.db import models
|
|||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from drf_spectacular.types import OpenApiTypes
|
||||||
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.fields import ChoiceField
|
from rest_framework.fields import ChoiceField
|
||||||
|
|
||||||
|
import InvenTree.ready
|
||||||
|
|
||||||
from .custom import get_logical_value
|
from .custom import get_logical_value
|
||||||
|
|
||||||
|
|
||||||
@ -73,6 +77,7 @@ class CustomChoiceField(serializers.ChoiceField):
|
|||||||
return field_info
|
return field_info
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema_field(OpenApiTypes.INT)
|
||||||
class ExtraCustomChoiceField(CustomChoiceField):
|
class ExtraCustomChoiceField(CustomChoiceField):
|
||||||
"""Custom Choice Field that returns value of status if empty.
|
"""Custom Choice Field that returns value of status if empty.
|
||||||
|
|
||||||
@ -138,14 +143,27 @@ class InvenTreeCustomStatusModelField(models.PositiveIntegerField):
|
|||||||
if self.status_class:
|
if self.status_class:
|
||||||
validators.append(CustomStatusCodeValidator(status_class=self.status_class))
|
validators.append(CustomStatusCodeValidator(status_class=self.status_class))
|
||||||
|
|
||||||
|
help_text = _('Additional status information for this item')
|
||||||
|
if InvenTree.ready.isGeneratingSchema():
|
||||||
|
help_text = (
|
||||||
|
help_text
|
||||||
|
+ '\n\n'
|
||||||
|
+ '\n'.join(
|
||||||
|
f'* `{value}` - {label}'
|
||||||
|
for value, label in self.status_class.items(custom=True)
|
||||||
|
)
|
||||||
|
+ "\n\nAdditional custom status keys may be retrieved from the corresponding 'status_retrieve' call."
|
||||||
|
)
|
||||||
|
|
||||||
custom_key_field = ExtraInvenTreeCustomStatusModelField(
|
custom_key_field = ExtraInvenTreeCustomStatusModelField(
|
||||||
default=None,
|
default=None,
|
||||||
verbose_name=_('Custom status key'),
|
verbose_name=_('Custom status key'),
|
||||||
help_text=_('Additional status information for this item'),
|
help_text=help_text,
|
||||||
validators=validators,
|
validators=validators,
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
cls.add_to_class(f'{name}_custom_key', custom_key_field)
|
cls.add_to_class(f'{name}_custom_key', custom_key_field)
|
||||||
self._custom_key_field = custom_key_field
|
self._custom_key_field = custom_key_field
|
||||||
|
|
||||||
|
@ -795,11 +795,7 @@ class PurchaseOrderLineItemReceiveSerializer(serializers.Serializer):
|
|||||||
allow_blank=True,
|
allow_blank=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
status = serializers.ChoiceField(
|
status = stock.serializers.StockStatusCustomSerializer(default=StockStatus.OK.value)
|
||||||
choices=StockStatus.items(custom=True),
|
|
||||||
default=StockStatus.OK.value,
|
|
||||||
label=_('Status'),
|
|
||||||
)
|
|
||||||
|
|
||||||
packaging = serializers.CharField(
|
packaging = serializers.CharField(
|
||||||
label=_('Packaging'),
|
label=_('Packaging'),
|
||||||
@ -1981,13 +1977,8 @@ class ReturnOrderLineItemReceiveSerializer(serializers.Serializer):
|
|||||||
label=_('Return order line item'),
|
label=_('Return order line item'),
|
||||||
)
|
)
|
||||||
|
|
||||||
status = serializers.ChoiceField(
|
status = stock.serializers.StockStatusCustomSerializer(
|
||||||
choices=stock.status_codes.StockStatus.items(custom=True),
|
default=None, required=False, allow_blank=True
|
||||||
default=None,
|
|
||||||
label=_('Status'),
|
|
||||||
help_text=_('Stock item status code'),
|
|
||||||
required=False,
|
|
||||||
allow_blank=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def validate_line_item(self, item):
|
def validate_line_item(self, item):
|
||||||
|
@ -16,6 +16,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
import structlog
|
import structlog
|
||||||
from djmoney.contrib.exchange.exceptions import MissingRate
|
from djmoney.contrib.exchange.exceptions import MissingRate
|
||||||
from djmoney.contrib.exchange.models import convert_money
|
from djmoney.contrib.exchange.models import convert_money
|
||||||
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from sql_util.utils import SubqueryCount, SubquerySum
|
from sql_util.utils import SubqueryCount, SubquerySum
|
||||||
from taggit.serializers import TagListSerializerField
|
from taggit.serializers import TagListSerializerField
|
||||||
@ -1300,6 +1301,21 @@ class PartStocktakeReportGenerateSerializer(serializers.Serializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema_field(
|
||||||
|
serializers.CharField(
|
||||||
|
help_text=_('Select currency from available options')
|
||||||
|
+ '\n\n'
|
||||||
|
+ '\n'.join(
|
||||||
|
f'* `{value}` - {label}'
|
||||||
|
for value, label in common.currency.currency_code_mappings()
|
||||||
|
)
|
||||||
|
+ "\n\nOther valid currencies may be found in the 'CURRENCY_CODES' global setting."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
class PartPricingCurrencySerializer(serializers.ChoiceField):
|
||||||
|
"""Serializer to allow annotating the schema to use String on currency fields."""
|
||||||
|
|
||||||
|
|
||||||
class PartPricingSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
class PartPricingSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
||||||
"""Serializer for Part pricing information."""
|
"""Serializer for Part pricing information."""
|
||||||
|
|
||||||
@ -1384,7 +1400,7 @@ class PartPricingSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
override_min_currency = serializers.ChoiceField(
|
override_min_currency = PartPricingCurrencySerializer(
|
||||||
label=_('Minimum price currency'),
|
label=_('Minimum price currency'),
|
||||||
read_only=False,
|
read_only=False,
|
||||||
required=False,
|
required=False,
|
||||||
@ -1399,7 +1415,7 @@ class PartPricingSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
override_max_currency = serializers.ChoiceField(
|
override_max_currency = PartPricingCurrencySerializer(
|
||||||
label=_('Maximum price currency'),
|
label=_('Maximum price currency'),
|
||||||
read_only=False,
|
read_only=False,
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -10,6 +10,7 @@ from django.db.models.functions import Coalesce
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
import structlog
|
import structlog
|
||||||
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
from sql_util.utils import SubqueryCount, SubquerySum
|
from sql_util.utils import SubqueryCount, SubquerySum
|
||||||
@ -984,6 +985,38 @@ class ConvertStockItemSerializer(serializers.Serializer):
|
|||||||
stock_item.convert_to_variant(part, request.user)
|
stock_item.convert_to_variant(part, request.user)
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema_field(
|
||||||
|
serializers.IntegerField(
|
||||||
|
help_text='Status key, chosen from the list of StockStatus keys'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
class StockStatusCustomSerializer(serializers.ChoiceField):
|
||||||
|
"""Serializer to allow annotating the schema to use int where custom values may be entered."""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""Initialize the status selector."""
|
||||||
|
if 'choices' not in kwargs:
|
||||||
|
kwargs['choices'] = stock.status_codes.StockStatus.items(custom=True)
|
||||||
|
|
||||||
|
if 'label' not in kwargs:
|
||||||
|
kwargs['label'] = _('Status')
|
||||||
|
|
||||||
|
if 'help_text' not in kwargs:
|
||||||
|
kwargs['help_text'] = _('Stock item status code')
|
||||||
|
|
||||||
|
if InvenTree.ready.isGeneratingSchema():
|
||||||
|
kwargs['help_text'] = (
|
||||||
|
kwargs['help_text']
|
||||||
|
+ '\n\n'
|
||||||
|
+ '\n'.join(
|
||||||
|
f'* `{value}` - {label}' for value, label in kwargs['choices']
|
||||||
|
)
|
||||||
|
+ "\n\nAdditional custom status keys may be retrieved from the 'stock_status_retrieve' call."
|
||||||
|
)
|
||||||
|
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ReturnStockItemSerializer(serializers.Serializer):
|
class ReturnStockItemSerializer(serializers.Serializer):
|
||||||
"""DRF serializer for returning a stock item from a customer."""
|
"""DRF serializer for returning a stock item from a customer."""
|
||||||
|
|
||||||
@ -1001,14 +1034,7 @@ class ReturnStockItemSerializer(serializers.Serializer):
|
|||||||
help_text=_('Destination location for returned item'),
|
help_text=_('Destination location for returned item'),
|
||||||
)
|
)
|
||||||
|
|
||||||
status = serializers.ChoiceField(
|
status = StockStatusCustomSerializer(default=None, required=False, allow_blank=True)
|
||||||
choices=stock.status_codes.StockStatus.items(custom=True),
|
|
||||||
default=None,
|
|
||||||
label=_('Status'),
|
|
||||||
help_text=_('Stock item status code'),
|
|
||||||
required=False,
|
|
||||||
allow_blank=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
notes = serializers.CharField(
|
notes = serializers.CharField(
|
||||||
label=_('Notes'),
|
label=_('Notes'),
|
||||||
@ -1058,10 +1084,8 @@ class StockChangeStatusSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
status = serializers.ChoiceField(
|
status = StockStatusCustomSerializer(
|
||||||
choices=stock.status_codes.StockStatus.items(custom=True),
|
default=stock.status_codes.StockStatus.OK.value
|
||||||
default=stock.status_codes.StockStatus.OK.value,
|
|
||||||
label=_('Status'),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
note = serializers.CharField(
|
note = serializers.CharField(
|
||||||
@ -1620,11 +1644,9 @@ class StockAdjustmentItemSerializer(serializers.Serializer):
|
|||||||
help_text=_('Batch code for this stock item'),
|
help_text=_('Batch code for this stock item'),
|
||||||
)
|
)
|
||||||
|
|
||||||
status = serializers.ChoiceField(
|
status = StockStatusCustomSerializer(
|
||||||
choices=stock_item_adjust_status_options(),
|
choices=stock_item_adjust_status_options(),
|
||||||
default=None,
|
default=None,
|
||||||
label=_('Status'),
|
|
||||||
help_text=_('Stock item status code'),
|
|
||||||
required=False,
|
required=False,
|
||||||
allow_blank=True,
|
allow_blank=True,
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user