• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

inventree / InvenTree / 4353746226

pending completion
4353746226

push

github

GitHub
Extend functionality of custom validation plugins (#4391)

73 of 73 new or added lines in 10 files covered. (100.0%)

25499 of 29092 relevant lines covered (87.65%)

0.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.56
/InvenTree/plugin/samples/integration/validation_sample.py
1
"""Sample plugin which demonstrates custom validation functionality"""
2

3
from datetime import datetime
1✔
4

5
from django.core.exceptions import ValidationError
1✔
6

7
from plugin import InvenTreePlugin
1✔
8
from plugin.mixins import SettingsMixin, ValidationMixin
1✔
9

10

11
class CustomValidationMixin(SettingsMixin, ValidationMixin, InvenTreePlugin):
1✔
12
    """A sample plugin class for demonstrating custom validation functions.
13

14
    Simple of examples of custom validator code.
15
    """
16

17
    NAME = "CustomValidator"
1✔
18
    SLUG = "validator"
1✔
19
    TITLE = "Custom Validator Plugin"
1✔
20
    DESCRIPTION = "A sample plugin for demonstrating custom validation functionality"
1✔
21
    VERSION = "0.2"
1✔
22

23
    SETTINGS = {
1✔
24
        'ILLEGAL_PART_CHARS': {
25
            'name': 'Illegal Part Characters',
26
            'description': 'Characters which are not allowed to appear in Part names',
27
            'default': '!@#$%^&*()~`'
28
        },
29
        'IPN_MUST_CONTAIN_Q': {
30
            'name': 'IPN Q Requirement',
31
            'description': 'Part IPN field must contain the character Q',
32
            'default': False,
33
            'validator': bool,
34
        },
35
        'SERIAL_MUST_BE_PALINDROME': {
36
            'name': 'Palindromic Serials',
37
            'description': 'Serial numbers must be palindromic',
38
            'default': False,
39
            'validator': bool,
40
        },
41
        'SERIAL_MUST_MATCH_PART': {
42
            'name': 'Serial must match part',
43
            'description': 'First letter of serial number must match first letter of part name',
44
            'default': False,
45
            'validator': bool,
46
        },
47
        'BATCH_CODE_PREFIX': {
48
            'name': 'Batch prefix',
49
            'description': 'Required prefix for batch code',
50
            'default': 'B',
51
        },
52
    }
53

54
    def validate_part_name(self, name: str, part):
1✔
55
        """Custom validation for Part name field:
56

57
        - Name must be shorter than the description field
58
        - Name cannot contain illegal characters
59

60
        These examples are silly, but serve to demonstrate how the feature could be used
61
        """
62

63
        if len(part.description) < len(name):
1✔
64
            raise ValidationError("Part description cannot be shorter than the name")
×
65

66
        illegal_chars = self.get_setting('ILLEGAL_PART_CHARS')
1✔
67

68
        for c in illegal_chars:
1✔
69
            if c in name:
1✔
70
                raise ValidationError(f"Illegal character in part name: '{c}'")
×
71

72
    def validate_part_ipn(self, ipn: str, part):
1✔
73
        """Validate part IPN
74

75
        These examples are silly, but serve to demonstrate how the feature could be used
76
        """
77

78
        if self.get_setting('IPN_MUST_CONTAIN_Q') and 'Q' not in ipn:
1✔
79
            raise ValidationError("IPN must contain 'Q'")
×
80

81
    def validate_serial_number(self, serial: str, part):
1✔
82
        """Validate serial number for a given StockItem
83

84
        These examples are silly, but serve to demonstrate how the feature could be used
85
        """
86

87
        if self.get_setting('SERIAL_MUST_BE_PALINDROME'):
1✔
88
            if serial != serial[::-1]:
×
89
                raise ValidationError("Serial must be a palindrome")
×
90

91
        if self.get_setting('SERIAL_MUST_MATCH_PART'):
1✔
92
            # Serial must start with the same letter as the linked part, for some reason
93
            if serial[0] != part.name[0]:
×
94
                raise ValidationError("Serial number must start with same letter as part")
×
95

96
    def validate_batch_code(self, batch_code: str, item):
1✔
97
        """Ensure that a particular batch code meets specification.
98

99
        These examples are silly, but serve to demonstrate how the feature could be used
100
        """
101

102
        prefix = self.get_setting('BATCH_CODE_PREFIX')
1✔
103

104
        if len(batch_code) > 0:
1✔
105
            if prefix and not batch_code.startswith(prefix):
1✔
106
                raise ValidationError(f"Batch code must start with '{prefix}'")
1✔
107

108
    def generate_batch_code(self):
1✔
109
        """Generate a new batch code."""
110

111
        now = datetime.now()
1✔
112
        return f"BATCH-{now.year}:{now.month}:{now.day}"
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc