diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index a276d62c54..c86027118c 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -39,7 +39,10 @@ class EditPartTestTemplateForm(HelperForm): fields = [ 'part', 'test_name', - 'required' + 'description', + 'required', + 'requires_value', + 'requires_attachment', ] diff --git a/InvenTree/part/migrations/0042_auto_20200518_0900.py b/InvenTree/part/migrations/0042_auto_20200518_0900.py new file mode 100644 index 0000000000..30b1734472 --- /dev/null +++ b/InvenTree/part/migrations/0042_auto_20200518_0900.py @@ -0,0 +1,33 @@ +# Generated by Django 3.0.5 on 2020-05-18 09:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0041_auto_20200517_0348'), + ] + + operations = [ + migrations.AddField( + model_name='parttesttemplate', + name='description', + field=models.CharField(help_text='Enter description for this test', max_length=100, null=True, verbose_name='Test Description'), + ), + migrations.AddField( + model_name='parttesttemplate', + name='requires_attachment', + field=models.BooleanField(default=False, help_text='Does this test require a file attachment when adding a test result?', verbose_name='Requires Attachment'), + ), + migrations.AddField( + model_name='parttesttemplate', + name='requires_value', + field=models.BooleanField(default=False, help_text='Does this test require a value when adding a test result?', verbose_name='Requires Value'), + ), + migrations.AlterField( + model_name='parttesttemplate', + name='test_name', + field=models.CharField(help_text='Enter a name for the test', max_length=100, verbose_name='Test Name'), + ), + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index d37d666be4..4ca77739ac 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1204,16 +1204,34 @@ class PartTestTemplate(models.Model): test_name = models.CharField( blank=False, max_length=100, - verbose_name=_("Test name"), + verbose_name=_("Test Name"), help_text=_("Enter a name for the test") ) + description = models.CharField( + blank=False, null=True, max_length=100, + verbose_name=_("Test Description"), + help_text=_("Enter description for this test") + ) + required = models.BooleanField( default=True, verbose_name=_("Required"), help_text=_("Is this test required to pass?") ) + requires_value = models.BooleanField( + default=False, + verbose_name=_("Requires Value"), + help_text=_("Does this test require a value when adding a test result?") + ) + + requires_attachment = models.BooleanField( + default=False, + verbose_name=_("Requires Attachment"), + help_text=_("Does this test require a file attachment when adding a test result?") + ) + class PartParameterTemplate(models.Model): """ diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 396f19ea58..64cf656f36 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -62,14 +62,20 @@ class PartTestTemplateSerializer(InvenTreeModelSerializer): Serializer for the PartTestTemplate class """ + key = serializers.CharField(read_only=True) + class Meta: model = PartTestTemplate fields = [ 'pk', + 'key', 'part', 'test_name', - 'required' + 'description', + 'required', + 'requires_value', + 'requires_attachment', ] diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index c50a58bea9..bb3621a7ac 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -1115,6 +1115,28 @@ class StockItemTestResult(models.Model): }) except (StockItem.DoesNotExist, StockItemAttachment.DoesNotExist): pass + + # If this test result corresponds to a template, check the requirements of the template + key = helpers.generateTestKey(self.test) + + templates = self.stock_item.part.getTestTemplates() + + for template in templates: + if key == template.key: + + if template.requires_value: + if not self.value: + raise ValidationError({ + "value": _("Value must be provided for this test"), + }) + + if template.requires_attachment: + if not self.attachment: + raise ValidationError({ + "attachment": _("Attachment must be uploaded for this test"), + }) + + break stock_item = models.ForeignKey( StockItem, diff --git a/InvenTree/templates/js/part.html b/InvenTree/templates/js/part.html index 528fc9aa93..1a40c7ad84 100644 --- a/InvenTree/templates/js/part.html +++ b/InvenTree/templates/js/part.html @@ -286,6 +286,14 @@ function loadPartTable(table, url, options={}) { }); } +function yesNoLabel(value) { + if (value) { + return `{% trans "YES" %}`; + } else { + return `{% trans "NO" %}`; + } +} + function loadPartTestTemplateTable(table, options) { /* @@ -332,16 +340,30 @@ function loadPartTestTemplateTable(table, options) { title: "{% trans "Test Name" %}", sortable: true, }, + { + field: 'description', + title: "{% trans "Description" %}", + }, { field: 'required', title: "{% trans 'Required' %}", sortable: true, formatter: function(value) { - if (value) { - return `{% trans "YES" %}`; - } else { - return `{% trans "NO" %}`; - } + return yesNoLabel(value); + } + }, + { + field: 'requires_value', + title: "{% trans "Requires Value" %}", + formatter: function(value) { + return yesNoLabel(value); + } + }, + { + field: 'requires_attachment', + title: "{% trans "Requires Attachment" %}", + formatter: function(value) { + return yesNoLabel(value); } }, {