diff --git a/src/backend/InvenTree/InvenTree/models.py b/src/backend/InvenTree/InvenTree/models.py index aaa2ca4fc1..2a0929128d 100644 --- a/src/backend/InvenTree/InvenTree/models.py +++ b/src/backend/InvenTree/InvenTree/models.py @@ -547,7 +547,7 @@ class InvenTreeParameterMixin(InvenTreePermissionCheckMixin, models.Model): Before deleting the model instance, delete any associated parameters. """ - self.parameters.all().delete() + self.parameters_list.all().delete() super().delete(*args, **kwargs) diff --git a/src/backend/InvenTree/common/models.py b/src/backend/InvenTree/common/models.py index 301aeb8612..addfe484cb 100644 --- a/src/backend/InvenTree/common/models.py +++ b/src/backend/InvenTree/common/models.py @@ -50,6 +50,7 @@ from taggit.managers import TaggableManager import common.validators import InvenTree.conversion +import InvenTree.exceptions import InvenTree.fields import InvenTree.helpers import InvenTree.models @@ -2585,6 +2586,15 @@ class Parameter( """Validate the Parameter before saving to the database.""" super().clean() + # Validate the parameter data against the template choices + if choices := self.template.get_choices(): + if self.data not in choices: + raise ValidationError({'data': _('Invalid choice for parameter value')}) + + self.calculate_numeric_value() + + # TODO: Check that the model_type for this parameter matches the template + # Validate the parameter data against the template units if ( get_global_setting( @@ -2599,18 +2609,21 @@ class Parameter( except ValidationError as e: raise ValidationError({'data': e.message}) - # Validate the parameter data against the template choices - if choices := self.template.get_choices(): - if self.data not in choices: - raise ValidationError({'data': _('Invalid choice for parameter value')}) + # Finally, run custom validation checks (via plugins) + from plugin import PluginMixinEnum, registry - self.calculate_numeric_value() - - # TODO: Check that the model_type for this parameter matches the template - - # TODO: Validation of units (check global setting) - - # TODO: Validate against plugins + for plugin in registry.with_mixin(PluginMixinEnum.VALIDATION): + # Note: The validate_part_parameter function may raise a ValidationError + try: + if hasattr(plugin, 'validate_parameter'): + result = plugin.validate_parameter(self, self.data) + if result: + break + except ValidationError as exc: + # Re-throw the ValidationError against the 'data' field + raise ValidationError({'data': exc.message}) + except Exception: + InvenTree.exceptions.log_error('validate_parameter', plugin=plugin.slug) def calculate_numeric_value(self): """Calculate a numeric value for the parameter data. diff --git a/src/backend/InvenTree/plugin/base/integration/ValidationMixin.py b/src/backend/InvenTree/plugin/base/integration/ValidationMixin.py index 0678bb3260..c67b88738e 100644 --- a/src/backend/InvenTree/plugin/base/integration/ValidationMixin.py +++ b/src/backend/InvenTree/plugin/base/integration/ValidationMixin.py @@ -227,9 +227,7 @@ class ValidationMixin: """ return None - def validate_part_parameter( - self, parameter: part.models.PartParameter, data: str - ) -> Optional[bool]: + def validate_parameter(self, parameter, data: str) -> Optional[bool]: """Validate a parameter value. Arguments: diff --git a/src/backend/InvenTree/plugin/samples/integration/validation_sample.py b/src/backend/InvenTree/plugin/samples/integration/validation_sample.py index 903cc59b34..7a8592f25d 100644 --- a/src/backend/InvenTree/plugin/samples/integration/validation_sample.py +++ b/src/backend/InvenTree/plugin/samples/integration/validation_sample.py @@ -111,8 +111,8 @@ class SampleValidatorPlugin(SettingsMixin, ValidationMixin, InvenTreePlugin): if self.get_setting('IPN_MUST_CONTAIN_Q') and 'Q' not in ipn: self.raise_error("IPN must contain 'Q'") - def validate_part_parameter(self, parameter, data): - """Validate part parameter data. + def validate_parameter(self, parameter, data): + """Validate parameter data. These examples are silly, but serve to demonstrate how the feature could be used """