mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-01 03:00:54 +00:00
[Plugin] Enhanced custom validation (#6410)
* Use registry.get_plugin() - Instead of registry.plugins.get() - get_plugin checks registry hash - performs registry reload if necessary * Add PluginValidationMixin class - Allows the entire model to be validated via plugins - Called on model.full_clean() - Called on model.save() * Update Validation sample plugin * Fix for InvenTreeTree models * Refactor build.models - Expose models to plugin validation * Update stock.models * Update more models - common.models - company.models * Update more models - label.models - order.models - part.models * More model updates * Update docs * Fix for potential plugin edge case - plugin slug is globally unique - do not use get_or_create with two lookup fields - will throw an IntegrityError if you change the name of a plugin * Inherit DiffMixin into PluginValidationMixin - Allows us to pass model diffs through to validation - Plugins can validate based on what has *changed* * Update documentation * Add get_plugin_config helper function * Bug fix * Bug fix * Update plugin hash when calling set_plugin_state * Working on unit testing * More unit testing * Move get_plugin_config into registry.py * Move extract_int into InvenTree.helpers * Fix log formatting * Update model definitions - Ensure there are no changes to the migrations * Comment out format line * Fix access to get_plugin_config * Fix tests for SimpleActionPlugin * More unit test fixes
This commit is contained in:
@ -26,20 +26,13 @@ from taggit.managers import TaggableManager
|
||||
|
||||
import common.models
|
||||
import InvenTree.helpers
|
||||
import InvenTree.models
|
||||
import InvenTree.ready
|
||||
import InvenTree.tasks
|
||||
import label.models
|
||||
import report.models
|
||||
from company import models as CompanyModels
|
||||
from InvenTree.fields import InvenTreeModelMoneyField, InvenTreeURLField
|
||||
from InvenTree.models import (
|
||||
InvenTreeAttachment,
|
||||
InvenTreeBarcodeMixin,
|
||||
InvenTreeNotesMixin,
|
||||
InvenTreeTree,
|
||||
MetadataMixin,
|
||||
extract_int,
|
||||
)
|
||||
from InvenTree.status_codes import (
|
||||
SalesOrderStatusGroups,
|
||||
StockHistoryCode,
|
||||
@ -53,7 +46,7 @@ from users.models import Owner
|
||||
logger = logging.getLogger('inventree')
|
||||
|
||||
|
||||
class StockLocationType(MetadataMixin, models.Model):
|
||||
class StockLocationType(InvenTree.models.MetadataMixin, models.Model):
|
||||
"""A type of stock location like Warehouse, room, shelf, drawer.
|
||||
|
||||
Attributes:
|
||||
@ -111,7 +104,9 @@ class StockLocationManager(TreeManager):
|
||||
return super().get_queryset()
|
||||
|
||||
|
||||
class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):
|
||||
class StockLocation(
|
||||
InvenTree.models.InvenTreeBarcodeMixin, InvenTree.models.InvenTreeTree
|
||||
):
|
||||
"""Organization tree for StockItem objects.
|
||||
|
||||
A "StockLocation" can be considered a warehouse, or storage location
|
||||
@ -352,9 +347,10 @@ def default_delete_on_deplete():
|
||||
|
||||
|
||||
class StockItem(
|
||||
InvenTreeBarcodeMixin,
|
||||
InvenTreeNotesMixin,
|
||||
MetadataMixin,
|
||||
InvenTree.models.InvenTreeBarcodeMixin,
|
||||
InvenTree.models.InvenTreeNotesMixin,
|
||||
InvenTree.models.MetadataMixin,
|
||||
InvenTree.models.PluginValidationMixin,
|
||||
common.models.MetaMixin,
|
||||
MPTTModel,
|
||||
):
|
||||
@ -450,7 +446,7 @@ class StockItem(
|
||||
serial_int = 0
|
||||
|
||||
if serial not in [None, '']:
|
||||
serial_int = extract_int(serial)
|
||||
serial_int = InvenTree.helpers.extract_int(serial)
|
||||
|
||||
self.serial_int = serial_int
|
||||
|
||||
@ -2193,7 +2189,7 @@ def after_save_stock_item(sender, instance: StockItem, created, **kwargs):
|
||||
instance.part.schedule_pricing_update(create=True)
|
||||
|
||||
|
||||
class StockItemAttachment(InvenTreeAttachment):
|
||||
class StockItemAttachment(InvenTree.models.InvenTreeAttachment):
|
||||
"""Model for storing file attachments against a StockItem object."""
|
||||
|
||||
@staticmethod
|
||||
@ -2210,7 +2206,7 @@ class StockItemAttachment(InvenTreeAttachment):
|
||||
)
|
||||
|
||||
|
||||
class StockItemTracking(models.Model):
|
||||
class StockItemTracking(InvenTree.models.InvenTreeModel):
|
||||
"""Stock tracking entry - used for tracking history of a particular StockItem.
|
||||
|
||||
Note: 2021-05-11
|
||||
@ -2274,7 +2270,7 @@ def rename_stock_item_test_result_attachment(instance, filename):
|
||||
)
|
||||
|
||||
|
||||
class StockItemTestResult(MetadataMixin, models.Model):
|
||||
class StockItemTestResult(InvenTree.models.InvenTreeMetadataModel):
|
||||
"""A StockItemTestResult records results of custom tests against individual StockItem objects.
|
||||
|
||||
This is useful for tracking unit acceptance tests, and particularly useful when integrated
|
||||
|
@ -22,7 +22,6 @@ import InvenTree.status_codes
|
||||
import part.models as part_models
|
||||
import stock.filters
|
||||
from company.serializers import SupplierPartSerializer
|
||||
from InvenTree.models import extract_int
|
||||
from InvenTree.serializers import InvenTreeCurrencySerializer, InvenTreeDecimalField
|
||||
from part.serializers import PartBriefSerializer
|
||||
|
||||
@ -114,7 +113,7 @@ class StockItemSerializerBrief(InvenTree.serializers.InvenTreeModelSerializer):
|
||||
|
||||
def validate_serial(self, value):
|
||||
"""Make sure serial is not to big."""
|
||||
if abs(extract_int(value)) > 0x7FFFFFFF:
|
||||
if abs(InvenTree.helpers.extract_int(value)) > 0x7FFFFFFF:
|
||||
raise serializers.ValidationError(_('Serial number is too large'))
|
||||
return value
|
||||
|
||||
|
@ -1117,6 +1117,8 @@ class TestResultTest(StockTestBase):
|
||||
"""Test duplicate item behaviour."""
|
||||
# Create an example stock item by copying one from the database (because we are lazy)
|
||||
|
||||
from plugin.registry import registry
|
||||
|
||||
StockItem.objects.rebuild()
|
||||
|
||||
item = StockItem.objects.get(pk=522)
|
||||
@ -1125,9 +1127,12 @@ class TestResultTest(StockTestBase):
|
||||
item.serial = None
|
||||
item.quantity = 50
|
||||
|
||||
# Try with an invalid batch code (according to sample validatoin plugin)
|
||||
# Try with an invalid batch code (according to sample validation plugin)
|
||||
item.batch = 'X234'
|
||||
|
||||
# Ensure that the sample validation plugin is activated
|
||||
registry.set_plugin_state('validator', True)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
item.save()
|
||||
|
||||
|
Reference in New Issue
Block a user