InvenTree/InvenTree/plugin/samples/integration/validation_sample.py

124 lines
4.3 KiB
Python

"""Sample plugin which demonstrates custom validation functionality"""
from datetime import datetime
from django.core.exceptions import ValidationError
from plugin import InvenTreePlugin
from plugin.mixins import SettingsMixin, ValidationMixin
class CustomValidationMixin(SettingsMixin, ValidationMixin, InvenTreePlugin):
"""A sample plugin class for demonstrating custom validation functions.
Simple of examples of custom validator code.
"""
NAME = "CustomValidator"
SLUG = "validator"
TITLE = "Custom Validator Plugin"
DESCRIPTION = "A sample plugin for demonstrating custom validation functionality"
VERSION = "0.3.0"
SETTINGS = {
'ILLEGAL_PART_CHARS': {
'name': 'Illegal Part Characters',
'description': 'Characters which are not allowed to appear in Part names',
'default': '!@#$%^&*()~`'
},
'IPN_MUST_CONTAIN_Q': {
'name': 'IPN Q Requirement',
'description': 'Part IPN field must contain the character Q',
'default': False,
'validator': bool,
},
'SERIAL_MUST_BE_PALINDROME': {
'name': 'Palindromic Serials',
'description': 'Serial numbers must be palindromic',
'default': False,
'validator': bool,
},
'SERIAL_MUST_MATCH_PART': {
'name': 'Serial must match part',
'description': 'First letter of serial number must match first letter of part name',
'default': False,
'validator': bool,
},
'BATCH_CODE_PREFIX': {
'name': 'Batch prefix',
'description': 'Required prefix for batch code',
'default': 'B',
},
}
def validate_part_name(self, name: str, part):
"""Custom validation for Part name field:
- Name must be shorter than the description field
- Name cannot contain illegal characters
These examples are silly, but serve to demonstrate how the feature could be used
"""
if len(part.description) < len(name):
raise ValidationError("Part description cannot be shorter than the name")
illegal_chars = self.get_setting('ILLEGAL_PART_CHARS')
for c in illegal_chars:
if c in name:
raise ValidationError(f"Illegal character in part name: '{c}'")
def validate_part_ipn(self, ipn: str, part):
"""Validate part IPN
These examples are silly, but serve to demonstrate how the feature could be used
"""
if self.get_setting('IPN_MUST_CONTAIN_Q') and 'Q' not in ipn:
raise ValidationError("IPN must contain 'Q'")
def validate_part_parameter(self, parameter, data):
"""Validate part parameter data.
These examples are silly, but serve to demonstrate how the feature could be used
"""
if parameter.template.name.lower() in ['length', 'width']:
d = int(data)
if d >= 100:
raise ValidationError("Value must be less than 100")
def validate_serial_number(self, serial: str, part):
"""Validate serial number for a given StockItem
These examples are silly, but serve to demonstrate how the feature could be used
"""
if self.get_setting('SERIAL_MUST_BE_PALINDROME'):
if serial != serial[::-1]:
raise ValidationError("Serial must be a palindrome")
if self.get_setting('SERIAL_MUST_MATCH_PART'):
# Serial must start with the same letter as the linked part, for some reason
if serial[0] != part.name[0]:
raise ValidationError("Serial number must start with same letter as part")
def validate_batch_code(self, batch_code: str, item):
"""Ensure that a particular batch code meets specification.
These examples are silly, but serve to demonstrate how the feature could be used
"""
prefix = self.get_setting('BATCH_CODE_PREFIX')
if len(batch_code) > 0:
if prefix and not batch_code.startswith(prefix):
raise ValidationError(f"Batch code must start with '{prefix}'")
def generate_batch_code(self):
"""Generate a new batch code."""
now = datetime.now()
return f"BATCH-{now.year}:{now.month}:{now.day}"