diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py index 10c2aa52c1..a01a9d90ac 100644 --- a/src/backend/InvenTree/InvenTree/api_version.py +++ b/src/backend/InvenTree/InvenTree/api_version.py @@ -1,13 +1,18 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 316 +INVENTREE_API_VERSION = 317 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v317 - 2025-02-26 : https://github.com/inventree/InvenTree/pull/9143 + - Default 'overdue' field to False in Build serializer + - Add allow_null to various fields in Build, Settings, Order, Part, and Stock serializers + - Add type hints to Users model to properly type fields + v316 - 2025-02-26 : https://github.com/inventree/InvenTree/pull/9185 - Allow 'icon' field to be nullified in the PartCategory API - Allow 'custom_icon' field to be nullified in the StockLocation API diff --git a/src/backend/InvenTree/build/serializers.py b/src/backend/InvenTree/build/serializers.py index 83f6c419da..671541e434 100644 --- a/src/backend/InvenTree/build/serializers.py +++ b/src/backend/InvenTree/build/serializers.py @@ -123,7 +123,7 @@ class BuildSerializer( quantity = InvenTreeDecimalField() - overdue = serializers.BooleanField(required=False, read_only=True) + overdue = serializers.BooleanField(read_only=True, default=False) issued_by_detail = UserSerializer(source='issued_by', read_only=True) @@ -132,11 +132,14 @@ class BuildSerializer( barcode_hash = serializers.CharField(read_only=True) project_code_label = serializers.CharField( - source='project_code.code', read_only=True, label=_('Project Code Label') + source='project_code.code', + read_only=True, + label=_('Project Code Label'), + allow_null=True, ) project_code_detail = ProjectCodeSerializer( - source='project_code', many=False, read_only=True + source='project_code', many=False, read_only=True, allow_null=True ) create_child_builds = serializers.BooleanField( diff --git a/src/backend/InvenTree/common/serializers.py b/src/backend/InvenTree/common/serializers.py index 407097388b..7341057c7b 100644 --- a/src/backend/InvenTree/common/serializers.py +++ b/src/backend/InvenTree/common/serializers.py @@ -69,11 +69,11 @@ class SettingsSerializer(InvenTreeModelSerializer): choices = serializers.SerializerMethodField() - model_name = serializers.CharField(read_only=True) + model_name = serializers.CharField(read_only=True, allow_null=True) model_filters = serializers.DictField(read_only=True) - api_url = serializers.CharField(read_only=True) + api_url = serializers.CharField(read_only=True, allow_null=True) value = SettingsValueField(allow_null=True) diff --git a/src/backend/InvenTree/company/serializers.py b/src/backend/InvenTree/company/serializers.py index e9f87d6eaa..edc6c12a13 100644 --- a/src/backend/InvenTree/company/serializers.py +++ b/src/backend/InvenTree/company/serializers.py @@ -160,6 +160,14 @@ class CompanySerializer( return queryset + address = serializers.CharField( + label=_( + 'Return the string representation for the primary address. This property exists for backwards compatibility.' + ), + allow_null=True, + read_only=True, + ) + primary_address = AddressSerializer(required=False, allow_null=True, read_only=True) image = InvenTreeImageSerializerField(required=False, allow_null=True) diff --git a/src/backend/InvenTree/order/serializers.py b/src/backend/InvenTree/order/serializers.py index 97a3fdbe14..8e4a4a400f 100644 --- a/src/backend/InvenTree/order/serializers.py +++ b/src/backend/InvenTree/order/serializers.py @@ -137,12 +137,15 @@ class AbstractOrderSerializer(DataImportExportSerializerMixin, serializers.Seria ) project_code_label = serializers.CharField( - source='project_code.code', read_only=True, label='Project Code Label' + source='project_code.code', + read_only=True, + label='Project Code Label', + allow_null=True, ) # Detail for project code field project_code_detail = ProjectCodeSerializer( - source='project_code', read_only=True, many=False + source='project_code', read_only=True, many=False, allow_null=True ) # Detail for address field diff --git a/src/backend/InvenTree/part/serializers.py b/src/backend/InvenTree/part/serializers.py index 6850259bd4..bf0b0ca4aa 100644 --- a/src/backend/InvenTree/part/serializers.py +++ b/src/backend/InvenTree/part/serializers.py @@ -386,7 +386,9 @@ class PartBriefSerializer(InvenTree.serializers.InvenTreeModelSerializer): self.fields.pop('pricing_min', None) self.fields.pop('pricing_max', None) - category_default_location = serializers.IntegerField(read_only=True) + category_default_location = serializers.IntegerField( + read_only=True, allow_null=True + ) image = InvenTree.serializers.InvenTreeImageSerializerField(read_only=True) thumbnail = serializers.CharField(source='get_thumbnail_url', read_only=True) @@ -969,7 +971,9 @@ class PartSerializer( unallocated_stock = serializers.FloatField( read_only=True, label=_('Unallocated Stock') ) - category_default_location = serializers.IntegerField(read_only=True) + category_default_location = serializers.IntegerField( + read_only=True, allow_null=True + ) variant_stock = serializers.FloatField(read_only=True, label=_('Variant Stock')) minimum_stock = serializers.FloatField( diff --git a/src/backend/InvenTree/stock/serializers.py b/src/backend/InvenTree/stock/serializers.py index d78d0336d6..4fd167f64c 100644 --- a/src/backend/InvenTree/stock/serializers.py +++ b/src/backend/InvenTree/stock/serializers.py @@ -593,13 +593,17 @@ class StockItemSerializer( ) SKU = serializers.CharField( - source='supplier_part.SKU', read_only=True, label=_('Supplier Part Number') + source='supplier_part.SKU', + read_only=True, + label=_('Supplier Part Number'), + allow_null=True, ) MPN = serializers.CharField( source='supplier_part.manufacturer_part.MPN', read_only=True, label=_('Manufacturer Part Number'), + allow_null=True, ) # Optional detail fields, which can be appended via query parameters @@ -657,11 +661,11 @@ class StockItemSerializer( ) purchase_order_reference = serializers.CharField( - source='purchase_order.reference', read_only=True + source='purchase_order.reference', read_only=True, allow_null=True ) sales_order_reference = serializers.CharField( - source='sales_order.reference', read_only=True + source='sales_order.reference', read_only=True, allow_null=True ) tags = TagListSerializerField(required=False) diff --git a/src/backend/InvenTree/users/models.py b/src/backend/InvenTree/users/models.py index 804c7ca3b8..4477217c84 100644 --- a/src/backend/InvenTree/users/models.py +++ b/src/backend/InvenTree/users/models.py @@ -137,7 +137,7 @@ class ApiToken(AuthToken, InvenTree.models.MetadataMixin): ) @staticmethod - def sanitize_name(name: str): + def sanitize_name(name: str) -> str: """Sanitize the provide name value.""" name = str(name).strip() @@ -155,7 +155,7 @@ class ApiToken(AuthToken, InvenTree.models.MetadataMixin): @property @admin.display(description=_('Token')) - def token(self): + def token(self) -> str: """Provide a redacted version of the token. The *raw* key value should never be displayed anywhere! @@ -170,7 +170,7 @@ class ApiToken(AuthToken, InvenTree.models.MetadataMixin): @property @admin.display(boolean=True, description=_('Expired')) - def expired(self): + def expired(self) -> bool: """Test if this token has expired.""" return ( self.expiry is not None and self.expiry < InvenTree.helpers.current_date() @@ -178,7 +178,7 @@ class ApiToken(AuthToken, InvenTree.models.MetadataMixin): @property @admin.display(boolean=True, description=_('Active')) - def active(self): + def active(self) -> bool: """Test if this token is active.""" return not self.revoked and not self.expired