diff --git a/InvenTree/part/fixtures/test_templates.yaml b/InvenTree/part/fixtures/test_templates.yaml new file mode 100644 index 0000000000..f939dea0c1 --- /dev/null +++ b/InvenTree/part/fixtures/test_templates.yaml @@ -0,0 +1,39 @@ +# Tests for the top-level "chair" part +- model: part.parttesttemplate + fields: + part: 10000 + test_name: Test strength of chair + +- model: part.parttesttemplate + fields: + part: 10000 + test_name: Apply paint + +- model: part.parttesttemplate + fields: + part: 10000 + test_name: Sew cushion + +- model: part.parttesttemplate + fields: + part: 10000 + test_name: Attach legs + +- model: part.parttesttemplate + fields: + part: 10000 + test_name: Record weight + required: false + +# Add some tests for one of the variants +- model: part.parttesttemplate + fields: + part: 10003 + test_name: Check that chair is green + required: true + +- model: part.parttesttemplate + fields: + part: 10004 + test_name: Check that chair is especially green + required: False \ No newline at end of file diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index fea0fbd79b..94e1efb202 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -990,6 +990,26 @@ class Part(MPTTModel): self.save() + def getTestTemplates(self, required=None, include_parent=True): + """ + Return a list of all test templates associated with this Part. + These are used for validation of a StockItem. + + args: + required: Set to True or False to filter by "required" status + include_parent: Set to True to traverse upwards + """ + + if include_parent: + tests = PartTestTemplate.objects.filter(part__in=self.get_ancestors(include_self=True)) + else: + tests = self.test_templates + + if required is not None: + tests = tests.filter(required=required) + + return tests + @property def attachment_count(self): """ Count the number of attachments for this part. @@ -1124,12 +1144,12 @@ class PartTestTemplate(models.Model): run on the model (refer to the validate_unique function). """ - def save(self): + def save(self, *args, **kwargs): self.validate_unique() self.clean() - super().save() + super().save(*args, **kwargs) def validate_unique(self, exclude=None): """ @@ -1139,7 +1159,7 @@ class PartTestTemplate(models.Model): super().validate_unique(exclude) # Get a list of all tests "above" this one - tests = self.objects.filter( + tests = PartTestTemplate.objects.filter( part__in=self.part.get_ancestors(include_self=True) ) diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 622f0af547..4418c64db5 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -5,10 +5,11 @@ from __future__ import unicode_literals from django.test import TestCase +from django.core.exceptions import ValidationError import os -from .models import Part +from .models import Part, PartTestTemplate from .models import rename_part_image, match_part_names from .templatetags import inventree_extras @@ -105,3 +106,61 @@ class PartTest(TestCase): matches = match_part_names('M2x5 LPHS') self.assertTrue(len(matches) > 0) + + +class TestTemplateTest(TestCase): + + fixtures = [ + 'category', + 'part', + 'location', + 'test_templates', + ] + + def test_template_count(self): + + chair = Part.objects.get(pk=10000) + + # Tests for the top-level chair object (nothing above it!) + self.assertEqual(chair.test_templates.count(), 5) + self.assertEqual(chair.getTestTemplates().count(), 5) + self.assertEqual(chair.getTestTemplates(required=True).count(), 4) + self.assertEqual(chair.getTestTemplates(required=False).count(), 1) + + # Test the lowest-level part which has more associated tests + variant = Part.objects.get(pk=10004) + + self.assertEqual(variant.getTestTemplates().count(), 7) + self.assertEqual(variant.getTestTemplates(include_parent=False).count(), 1) + self.assertEqual(variant.getTestTemplates(required=True).count(), 5) + + def test_uniqueness(self): + # Test names must be unique for this part and also parts above + + variant = Part.objects.get(pk=10004) + + with self.assertRaises(ValidationError): + PartTestTemplate.objects.create( + part=variant, + test_name='Record weight' + ) + + with self.assertRaises(ValidationError): + PartTestTemplate.objects.create( + part=variant, + test_name='Check that chair is especially green' + ) + + # Also should fail if we attempt to create a test that would generate the same key + with self.assertRaises(ValidationError): + PartTestTemplate.objects.create( + part=variant, + test_name='ReCoRD weiGHT ' + ) + + # But we should be able to create a new one! + n = variant.getTestTemplates().count() + + PartTestTemplate.objects.create(part=variant, test_name='A Sample Test') + + self.assertEqual(variant.getTestTemplates().count(), n + 1) \ No newline at end of file