124 lines
4.3 KiB
Python
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}"
|