2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-27 19:16:44 +00:00

Schema: Mark nullable fields (#9546)

* Add allow_null to nullable fields

* Fix serializer for InfoApi, add nullable flags

* Bump api version

* Fix incorrectly replaced required tag
This commit is contained in:
Joe Rogers 2025-04-21 08:59:23 +02:00 committed by GitHub
parent bd74044ed9
commit 0de8e61d53
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 120 additions and 63 deletions

View File

@ -229,11 +229,11 @@ class InfoApiSerializer(serializers.Serializer):
logo = serializers.CharField()
splash = serializers.CharField()
login_message = serializers.CharField()
navbar_message = serializers
login_message = serializers.CharField(allow_null=True)
navbar_message = serializers.CharField(allow_null=True)
server = serializers.CharField(read_only=True)
id = serializers.CharField(read_only=True)
id = serializers.CharField(read_only=True, allow_null=True)
version = serializers.CharField(read_only=True)
instance = serializers.CharField(read_only=True)
apiVersion = serializers.IntegerField(read_only=True) # noqa: N815
@ -246,15 +246,13 @@ class InfoApiSerializer(serializers.Serializer):
email_configured = serializers.BooleanField(read_only=True)
debug_mode = serializers.BooleanField(read_only=True)
docker_mode = serializers.BooleanField(read_only=True)
default_locale = serializers.ChoiceField(
choices=settings.LOCALE_CODES, read_only=True
)
default_locale = serializers.CharField(read_only=True)
customize = CustomizeSerializer(read_only=True)
system_health = serializers.BooleanField(read_only=True)
database = serializers.CharField(read_only=True)
platform = serializers.CharField(read_only=True)
installer = serializers.CharField(read_only=True)
target = serializers.CharField(read_only=True)
target = serializers.CharField(read_only=True, allow_null=True)
django_admin = serializers.CharField(read_only=True)
settings = SettingsSerializer(read_only=True, many=False)

View File

@ -1,13 +1,16 @@
"""InvenTree API version information."""
# InvenTree API version
INVENTREE_API_VERSION = 339
INVENTREE_API_VERSION = 340
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """
v340 -> 2025-04-15 : https://github.com/inventree/InvenTree/pull/9546
- Add nullable to various fields to make them not required
v339 -> 2025-04-15 : https://github.com/inventree/InvenTree/pull/9283
- Remove need for source in /plugins/ui/features

View File

@ -1431,7 +1431,12 @@ class BuildLineSerializer(DataImportExportSerializerMixin, InvenTreeModelSeriali
pricing=False,
)
build_detail = BuildSerializer(
label=_('Build'), source='build', part_detail=False, many=False, read_only=True
label=_('Build'),
source='build',
part_detail=False,
many=False,
read_only=True,
allow_null=True,
)
# Annotated (calculated) fields

View File

@ -812,6 +812,4 @@ class DataOutputSerializer(InvenTreeModelSerializer):
user_detail = UserSerializer(source='user', read_only=True, many=False)
output = InvenTreeAttachmentSerializerField(
required=False, allow_null=True, read_only=True
)
output = InvenTreeAttachmentSerializerField(allow_null=True, read_only=True)

View File

@ -169,7 +169,7 @@ class CompanySerializer(
read_only=True,
)
primary_address = AddressSerializer(required=False, allow_null=True, read_only=True)
primary_address = AddressSerializer(allow_null=True, read_only=True)
image = InvenTreeImageSerializerField(required=False, allow_null=True)
@ -463,7 +463,7 @@ class SupplierPartSerializer(
)
MPN = serializers.CharField(
source='manufacturer_part.MPN', read_only=True, label=_('MPN')
source='manufacturer_part.MPN', read_only=True, allow_null=True, label=_('MPN')
)
# Date fields

View File

@ -65,7 +65,7 @@ class DataImporterModelSerializer(serializers.Serializer):
serializer = serializers.CharField(read_only=True)
model_type = serializers.CharField(read_only=True)
api_url = serializers.URLField(read_only=True)
api_url = serializers.URLField(read_only=True, allow_null=True)
class DataImporterModelList(APIView):

View File

@ -112,11 +112,13 @@ class AbstractOrderSerializer(DataImportExportSerializerMixin, serializers.Seria
import_exclude_fields = ['notes', 'duplicate']
# Number of line items in this order
line_items = serializers.IntegerField(read_only=True, label=_('Line Items'))
line_items = serializers.IntegerField(
read_only=True, allow_null=True, label=_('Line Items')
)
# Number of completed line items (this is an annotated field)
completed_lines = serializers.IntegerField(
read_only=True, label=_('Completed Lines')
read_only=True, allow_null=True, label=_('Completed Lines')
)
# Human-readable status text (read-only)
@ -156,7 +158,7 @@ class AbstractOrderSerializer(DataImportExportSerializerMixin, serializers.Seria
)
# Boolean field indicating if this order is overdue (Note: must be annotated)
overdue = serializers.BooleanField(required=False, read_only=True)
overdue = serializers.BooleanField(read_only=True, allow_null=True)
barcode_hash = serializers.CharField(read_only=True)
@ -609,7 +611,7 @@ class PurchaseOrderLineItemSerializer(
received = serializers.FloatField(default=0, read_only=True)
overdue = serializers.BooleanField(required=False, read_only=True)
overdue = serializers.BooleanField(read_only=True, allow_null=True)
total_price = serializers.FloatField(read_only=True)
@ -632,7 +634,7 @@ class PurchaseOrderLineItemSerializer(
)
destination_detail = stock.serializers.LocationBriefSerializer(
source='get_destination', read_only=True
source='get_destination', read_only=True, allow_null=True
)
purchase_price_currency = InvenTreeCurrencySerializer(
@ -652,14 +654,22 @@ class PurchaseOrderLineItemSerializer(
write_only=True,
)
sku = serializers.CharField(source='part.SKU', read_only=True, label=_('SKU'))
sku = serializers.CharField(
source='part.SKU', read_only=True, allow_null=True, label=_('SKU')
)
mpn = serializers.CharField(
source='part.manufacturer_part.MPN', read_only=True, label=_('MPN')
source='part.manufacturer_part.MPN',
read_only=True,
allow_null=True,
label=_('MPN'),
)
ipn = serializers.CharField(
source='part.part.IPN', read_only=True, label=_('Internal Part Number')
source='part.part.IPN',
read_only=True,
allow_null=True,
label=_('Internal Part Number'),
)
internal_part = serializers.PrimaryKeyRelatedField(
@ -1078,10 +1088,12 @@ class SalesOrderSerializer(
source='customer', many=False, read_only=True, allow_null=True
)
shipments_count = serializers.IntegerField(read_only=True, label=_('Shipments'))
shipments_count = serializers.IntegerField(
read_only=True, allow_null=True, label=_('Shipments')
)
completed_shipments_count = serializers.IntegerField(
read_only=True, label=_('Completed Shipments')
read_only=True, allow_null=True, label=_('Completed Shipments')
)
@ -1253,7 +1265,7 @@ class SalesOrderLineItemSerializer(
)
# Annotated fields
overdue = serializers.BooleanField(required=False, read_only=True)
overdue = serializers.BooleanField(read_only=True, allow_null=True)
available_stock = serializers.FloatField(read_only=True)
available_variant_stock = serializers.FloatField(read_only=True)
on_order = serializers.FloatField(label=_('On Order'), read_only=True)
@ -1316,7 +1328,7 @@ class SalesOrderShipmentSerializer(NotesFieldMixin, InvenTreeModelSerializer):
return queryset
allocated_items = serializers.IntegerField(
read_only=True, label=_('Allocated Items')
read_only=True, allow_null=True, label=_('Allocated Items')
)
order_detail = SalesOrderSerializer(
@ -1389,7 +1401,7 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer):
order = serializers.PrimaryKeyRelatedField(
source='line.order', many=False, read_only=True
)
serial = serializers.CharField(source='get_serial', read_only=True)
serial = serializers.CharField(source='get_serial', read_only=True, allow_null=True)
quantity = serializers.FloatField(read_only=False)
location = serializers.PrimaryKeyRelatedField(
source='item.location', many=False, read_only=True

View File

@ -126,9 +126,13 @@ class CategorySerializer(
help_text=_('Parent part category'),
)
part_count = serializers.IntegerField(read_only=True, label=_('Parts'))
part_count = serializers.IntegerField(
read_only=True, allow_null=True, label=_('Parts')
)
subcategories = serializers.IntegerField(read_only=True, label=_('Subcategories'))
subcategories = serializers.IntegerField(
read_only=True, allow_null=True, label=_('Subcategories')
)
level = serializers.IntegerField(read_only=True)
@ -149,7 +153,7 @@ class CategorySerializer(
max_length=100,
)
parent_default_location = serializers.IntegerField(read_only=True)
parent_default_location = serializers.IntegerField(read_only=True, allow_null=True)
class CategoryTree(InvenTree.serializers.InvenTreeModelSerializer):
@ -335,6 +339,7 @@ class PartParameterTemplateSerializer(
parts = serializers.IntegerField(
read_only=True,
allow_null=True,
label=_('Parts'),
help_text=_('Number of parts using this template'),
)
@ -396,7 +401,9 @@ class PartBriefSerializer(InvenTree.serializers.InvenTreeModelSerializer):
read_only=True, allow_null=True
)
image = InvenTree.serializers.InvenTreeImageSerializerField(read_only=True)
image = InvenTree.serializers.InvenTreeImageSerializerField(
read_only=True, allow_null=True
)
thumbnail = serializers.CharField(source='get_thumbnail_url', read_only=True)
IPN = serializers.CharField(
@ -924,25 +931,47 @@ class PartSerializer(
)
# Annotated fields
allocated_to_build_orders = serializers.FloatField(read_only=True)
allocated_to_sales_orders = serializers.FloatField(read_only=True)
building = serializers.FloatField(read_only=True, label=_('Building'))
in_stock = serializers.FloatField(read_only=True, label=_('In Stock'))
ordering = serializers.FloatField(read_only=True, label=_('On Order'))
required_for_build_orders = serializers.IntegerField(read_only=True)
required_for_sales_orders = serializers.IntegerField(read_only=True)
stock_item_count = serializers.IntegerField(read_only=True, label=_('Stock Items'))
revision_count = serializers.IntegerField(read_only=True, label=_('Revisions'))
suppliers = serializers.IntegerField(read_only=True, label=_('Suppliers'))
total_in_stock = serializers.FloatField(read_only=True, label=_('Total Stock'))
external_stock = serializers.FloatField(read_only=True, label=_('External Stock'))
allocated_to_build_orders = serializers.FloatField(read_only=True, allow_null=True)
allocated_to_sales_orders = serializers.FloatField(read_only=True, allow_null=True)
building = serializers.FloatField(
read_only=True, allow_null=True, label=_('Building')
)
in_stock = serializers.FloatField(
read_only=True, allow_null=True, label=_('In Stock')
)
ordering = serializers.FloatField(
read_only=True, allow_null=True, label=_('On Order')
)
required_for_build_orders = serializers.IntegerField(
read_only=True, allow_null=True
)
required_for_sales_orders = serializers.IntegerField(
read_only=True, allow_null=True
)
stock_item_count = serializers.IntegerField(
read_only=True, allow_null=True, label=_('Stock Items')
)
revision_count = serializers.IntegerField(
read_only=True, allow_null=True, label=_('Revisions')
)
suppliers = serializers.IntegerField(
read_only=True, allow_null=True, label=_('Suppliers')
)
total_in_stock = serializers.FloatField(
read_only=True, allow_null=True, label=_('Total Stock')
)
external_stock = serializers.FloatField(
read_only=True, allow_null=True, label=_('External Stock')
)
unallocated_stock = serializers.FloatField(
read_only=True, label=_('Unallocated Stock')
read_only=True, allow_null=True, label=_('Unallocated Stock')
)
category_default_location = serializers.IntegerField(
read_only=True, allow_null=True
)
variant_stock = serializers.FloatField(read_only=True, label=_('Variant Stock'))
variant_stock = serializers.FloatField(
read_only=True, allow_null=True, label=_('Variant Stock')
)
minimum_stock = serializers.FloatField(
required=False, label=_('Minimum Stock'), default=0
@ -1657,11 +1686,17 @@ class BomItemSerializer(
allow_null=True,
)
on_order = serializers.FloatField(label=_('On Order'), read_only=True)
on_order = serializers.FloatField(
label=_('On Order'), read_only=True, allow_null=True
)
building = serializers.FloatField(label=_('In Production'), read_only=True)
building = serializers.FloatField(
label=_('In Production'), read_only=True, allow_null=True
)
can_build = serializers.FloatField(label=_('Can Build'), read_only=True)
can_build = serializers.FloatField(
label=_('Can Build'), read_only=True, allow_null=True
)
# Cached pricing fields
pricing_min = InvenTree.serializers.InvenTreeMoneySerializer(
@ -1684,12 +1719,14 @@ class BomItemSerializer(
)
# Annotated fields for available stock
available_stock = serializers.FloatField(label=_('Available Stock'), read_only=True)
available_stock = serializers.FloatField(
label=_('Available Stock'), read_only=True, allow_null=True
)
available_substitute_stock = serializers.FloatField(read_only=True)
available_variant_stock = serializers.FloatField(read_only=True)
available_substitute_stock = serializers.FloatField(read_only=True, allow_null=True)
available_variant_stock = serializers.FloatField(read_only=True, allow_null=True)
external_stock = serializers.FloatField(read_only=True)
external_stock = serializers.FloatField(read_only=True, allow_null=True)
@staticmethod
def annotate_queryset(queryset):

View File

@ -655,20 +655,20 @@ class StockItemSerializer(
# Annotated fields
allocated = serializers.FloatField(
required=False, read_only=True, label=_('Allocated Quantity')
read_only=True, allow_null=True, label=_('Allocated Quantity')
)
expired = serializers.BooleanField(
required=False, read_only=True, label=_('Expired')
read_only=True, allow_null=True, label=_('Expired')
)
installed_items = serializers.IntegerField(
read_only=True, required=False, label=_('Installed Items')
read_only=True, allow_null=True, label=_('Installed Items')
)
child_items = serializers.IntegerField(
read_only=True, required=False, label=_('Child Items')
read_only=True, allow_null=True, label=_('Child Items')
)
stale = serializers.BooleanField(required=False, read_only=True, label=_('Stale'))
stale = serializers.BooleanField(read_only=True, allow_null=True, label=_('Stale'))
tracking_items = serializers.IntegerField(
read_only=True, required=False, label=_('Tracking Items')
read_only=True, allow_null=True, label=_('Tracking Items')
)
purchase_price = InvenTree.serializers.InvenTreeMoneySerializer(
@ -1161,7 +1161,7 @@ class StockLocationTypeSerializer(InvenTree.serializers.InvenTreeModelSerializer
read_only_fields = ['location_count']
location_count = serializers.IntegerField(read_only=True)
location_count = serializers.IntegerField(read_only=True, allow_null=True)
@staticmethod
def annotate_queryset(queryset):
@ -1273,7 +1273,7 @@ class LocationSerializer(
# Detail for location type
location_type_detail = StockLocationTypeSerializer(
source='location_type', read_only=True, many=False
source='location_type', read_only=True, allow_null=True, many=False
)

View File

@ -283,9 +283,13 @@ class GroupSerializer(InvenTreeModelSerializer):
"""Return a list of permissions associated with the group."""
return generate_permission_dict(group.permissions.all())
roles = RuleSetSerializer(source='rule_sets', many=True, read_only=True)
roles = RuleSetSerializer(
source='rule_sets', many=True, read_only=True, allow_null=True
)
users = UserSerializer(source='user_set', many=True, read_only=True)
users = UserSerializer(
source='user_set', many=True, read_only=True, allow_null=True
)
class ExtendedUserSerializer(UserSerializer):