diff --git a/src/backend/InvenTree/common/models.py b/src/backend/InvenTree/common/models.py index a118258173..4cb97d19a8 100644 --- a/src/backend/InvenTree/common/models.py +++ b/src/backend/InvenTree/common/models.py @@ -3403,7 +3403,30 @@ class Attachment(InvenTree.models.MetadataMixin, InvenTree.models.InvenTreeModel class InvenTreeCustomUserStateModel(models.Model): - """Custom model to extends any registered state with extra custom, user defined states.""" + """Custom model to extends any registered state with extra custom, user defined states. + + Fields: + reference_status: Status set that is extended with this custom state + logical_key: State logical key that is equal to this custom state in business logic + key: Numerical value that will be saved in the models database + name: Name of the state (must be uppercase and a valid variable identifier) + label: Label that will be displayed in the frontend (human readable) + color: Color that will be displayed in the frontend + + """ + + reference_status = models.CharField( + max_length=250, + verbose_name=_('Reference Status Set'), + help_text=_('Status set that is extended with this custom state'), + ) + + logical_key = models.IntegerField( + verbose_name=_('Logical Key'), + help_text=_( + 'State logical key that is equal to this custom state in business logic' + ), + ) key = models.IntegerField( verbose_name=_('Value'), @@ -3411,7 +3434,13 @@ class InvenTreeCustomUserStateModel(models.Model): ) name = models.CharField( - max_length=250, verbose_name=_('Name'), help_text=_('Name of the state') + max_length=250, + verbose_name=_('Name'), + help_text=_('Name of the state'), + validators=[ + common.validators.validate_uppercase, + common.validators.validate_variable_string, + ], ) label = models.CharField( @@ -3428,13 +3457,6 @@ class InvenTreeCustomUserStateModel(models.Model): help_text=_('Color that will be displayed in the frontend'), ) - logical_key = models.IntegerField( - verbose_name=_('Logical Key'), - help_text=_( - 'State logical key that is equal to this custom state in business logic' - ), - ) - model = models.ForeignKey( ContentType, on_delete=models.SET_NULL, @@ -3444,12 +3466,6 @@ class InvenTreeCustomUserStateModel(models.Model): help_text=_('Model this state is associated with'), ) - reference_status = models.CharField( - max_length=250, - verbose_name=_('Reference Status Set'), - help_text=_('Status set that is extended with this custom state'), - ) - class Meta: """Metaclass options for this mixin.""" @@ -3493,17 +3509,21 @@ class InvenTreeCustomUserStateModel(models.Model): get_custom_classes(include_custom=False), ) ) + if len(ref_set) == 0: raise ValidationError({ 'reference_status': _('Reference status set not found') }) + ref_set = ref_set[0] + if self.key in ref_set.keys(): # noqa: SIM118 raise ValidationError({ 'key': _( 'Key must be different from the logical keys of the reference status' ) }) + if self.logical_key not in ref_set.keys(): # noqa: SIM118 raise ValidationError({ 'logical_key': _( diff --git a/src/backend/InvenTree/common/serializers.py b/src/backend/InvenTree/common/serializers.py index ed134d2707..29e22dac58 100644 --- a/src/backend/InvenTree/common/serializers.py +++ b/src/backend/InvenTree/common/serializers.py @@ -335,6 +335,7 @@ class CustomStateSerializer(DataImportExportSerializerMixin, InvenTreeModelSeria ] model_name = serializers.CharField(read_only=True, source='model.name') + reference_status = serializers.ChoiceField( choices=generic.states.custom.state_reference_mappings() ) diff --git a/src/backend/InvenTree/common/validators.py b/src/backend/InvenTree/common/validators.py index efb82e692e..02f8f7781a 100644 --- a/src/backend/InvenTree/common/validators.py +++ b/src/backend/InvenTree/common/validators.py @@ -113,3 +113,17 @@ def validate_icon(name: Union[str, None]): return common.icons.validate_icon(name) + + +def validate_uppercase(value: str): + """Ensure that the provided value is uppercase.""" + value = str(value) + + if value != value.upper(): + raise ValidationError(_('Value must be uppercase')) + + +def validate_variable_string(value: str): + """The passed value must be a valid variable identifier string.""" + if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', value): + raise ValidationError(_('Value must be a valid variable identifier'))