2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 03:26:45 +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() logo = serializers.CharField()
splash = serializers.CharField() splash = serializers.CharField()
login_message = serializers.CharField() login_message = serializers.CharField(allow_null=True)
navbar_message = serializers navbar_message = serializers.CharField(allow_null=True)
server = serializers.CharField(read_only=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) version = serializers.CharField(read_only=True)
instance = serializers.CharField(read_only=True) instance = serializers.CharField(read_only=True)
apiVersion = serializers.IntegerField(read_only=True) # noqa: N815 apiVersion = serializers.IntegerField(read_only=True) # noqa: N815
@ -246,15 +246,13 @@ class InfoApiSerializer(serializers.Serializer):
email_configured = serializers.BooleanField(read_only=True) email_configured = serializers.BooleanField(read_only=True)
debug_mode = serializers.BooleanField(read_only=True) debug_mode = serializers.BooleanField(read_only=True)
docker_mode = serializers.BooleanField(read_only=True) docker_mode = serializers.BooleanField(read_only=True)
default_locale = serializers.ChoiceField( default_locale = serializers.CharField(read_only=True)
choices=settings.LOCALE_CODES, read_only=True
)
customize = CustomizeSerializer(read_only=True) customize = CustomizeSerializer(read_only=True)
system_health = serializers.BooleanField(read_only=True) system_health = serializers.BooleanField(read_only=True)
database = serializers.CharField(read_only=True) database = serializers.CharField(read_only=True)
platform = serializers.CharField(read_only=True) platform = serializers.CharField(read_only=True)
installer = 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) django_admin = serializers.CharField(read_only=True)
settings = SettingsSerializer(read_only=True, many=False) settings = SettingsSerializer(read_only=True, many=False)

View File

@ -1,13 +1,16 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # 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.""" """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 = """
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 v339 -> 2025-04-15 : https://github.com/inventree/InvenTree/pull/9283
- Remove need for source in /plugins/ui/features - Remove need for source in /plugins/ui/features

View File

@ -1431,7 +1431,12 @@ class BuildLineSerializer(DataImportExportSerializerMixin, InvenTreeModelSeriali
pricing=False, pricing=False,
) )
build_detail = BuildSerializer( 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 # Annotated (calculated) fields

View File

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

View File

@ -169,7 +169,7 @@ class CompanySerializer(
read_only=True, 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) image = InvenTreeImageSerializerField(required=False, allow_null=True)
@ -463,7 +463,7 @@ class SupplierPartSerializer(
) )
MPN = serializers.CharField( 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 # Date fields

View File

@ -65,7 +65,7 @@ class DataImporterModelSerializer(serializers.Serializer):
serializer = serializers.CharField(read_only=True) serializer = serializers.CharField(read_only=True)
model_type = 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): class DataImporterModelList(APIView):

View File

@ -112,11 +112,13 @@ class AbstractOrderSerializer(DataImportExportSerializerMixin, serializers.Seria
import_exclude_fields = ['notes', 'duplicate'] import_exclude_fields = ['notes', 'duplicate']
# Number of line items in this order # 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) # Number of completed line items (this is an annotated field)
completed_lines = serializers.IntegerField( 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) # 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) # 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) barcode_hash = serializers.CharField(read_only=True)
@ -609,7 +611,7 @@ class PurchaseOrderLineItemSerializer(
received = serializers.FloatField(default=0, read_only=True) 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) total_price = serializers.FloatField(read_only=True)
@ -632,7 +634,7 @@ class PurchaseOrderLineItemSerializer(
) )
destination_detail = stock.serializers.LocationBriefSerializer( destination_detail = stock.serializers.LocationBriefSerializer(
source='get_destination', read_only=True source='get_destination', read_only=True, allow_null=True
) )
purchase_price_currency = InvenTreeCurrencySerializer( purchase_price_currency = InvenTreeCurrencySerializer(
@ -652,14 +654,22 @@ class PurchaseOrderLineItemSerializer(
write_only=True, 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( 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( 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( internal_part = serializers.PrimaryKeyRelatedField(
@ -1078,10 +1088,12 @@ class SalesOrderSerializer(
source='customer', many=False, read_only=True, allow_null=True 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( 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 # 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_stock = serializers.FloatField(read_only=True)
available_variant_stock = serializers.FloatField(read_only=True) available_variant_stock = serializers.FloatField(read_only=True)
on_order = serializers.FloatField(label=_('On Order'), read_only=True) on_order = serializers.FloatField(label=_('On Order'), read_only=True)
@ -1316,7 +1328,7 @@ class SalesOrderShipmentSerializer(NotesFieldMixin, InvenTreeModelSerializer):
return queryset return queryset
allocated_items = serializers.IntegerField( allocated_items = serializers.IntegerField(
read_only=True, label=_('Allocated Items') read_only=True, allow_null=True, label=_('Allocated Items')
) )
order_detail = SalesOrderSerializer( order_detail = SalesOrderSerializer(
@ -1389,7 +1401,7 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer):
order = serializers.PrimaryKeyRelatedField( order = serializers.PrimaryKeyRelatedField(
source='line.order', many=False, read_only=True 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) quantity = serializers.FloatField(read_only=False)
location = serializers.PrimaryKeyRelatedField( location = serializers.PrimaryKeyRelatedField(
source='item.location', many=False, read_only=True source='item.location', many=False, read_only=True

View File

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

View File

@ -655,20 +655,20 @@ class StockItemSerializer(
# Annotated fields # Annotated fields
allocated = serializers.FloatField( allocated = serializers.FloatField(
required=False, read_only=True, label=_('Allocated Quantity') read_only=True, allow_null=True, label=_('Allocated Quantity')
) )
expired = serializers.BooleanField( expired = serializers.BooleanField(
required=False, read_only=True, label=_('Expired') read_only=True, allow_null=True, label=_('Expired')
) )
installed_items = serializers.IntegerField( 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( 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( 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( purchase_price = InvenTree.serializers.InvenTreeMoneySerializer(
@ -1161,7 +1161,7 @@ class StockLocationTypeSerializer(InvenTree.serializers.InvenTreeModelSerializer
read_only_fields = ['location_count'] read_only_fields = ['location_count']
location_count = serializers.IntegerField(read_only=True) location_count = serializers.IntegerField(read_only=True, allow_null=True)
@staticmethod @staticmethod
def annotate_queryset(queryset): def annotate_queryset(queryset):
@ -1273,7 +1273,7 @@ class LocationSerializer(
# Detail for location type # Detail for location type
location_type_detail = StockLocationTypeSerializer( 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 a list of permissions associated with the group."""
return generate_permission_dict(group.permissions.all()) 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): class ExtendedUserSerializer(UserSerializer):