From 157cbbead5043e091a060fae7d7938904ee155c1 Mon Sep 17 00:00:00 2001
From: Joe Rogers <1337joe@users.noreply.github.com>
Date: Fri, 28 Feb 2025 09:15:35 +0100
Subject: [PATCH] Schema cleanup tmp (#9143)

* Add type hints for name, address, expired, and active

* Add nullable to various fields that return null in the test dataset

* Removed nullable type hint, add default boolean value instead of nullable

* Bump schema version

* Add schema version notes, add localized tags for doc string

---------

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
---
 src/backend/InvenTree/InvenTree/api_version.py |  7 ++++++-
 src/backend/InvenTree/build/serializers.py     |  9 ++++++---
 src/backend/InvenTree/common/serializers.py    |  4 ++--
 src/backend/InvenTree/company/serializers.py   |  8 ++++++++
 src/backend/InvenTree/order/serializers.py     |  7 +++++--
 src/backend/InvenTree/part/serializers.py      |  8 ++++++--
 src/backend/InvenTree/stock/serializers.py     | 10 +++++++---
 src/backend/InvenTree/users/models.py          |  8 ++++----
 8 files changed, 44 insertions(+), 17 deletions(-)

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