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);
}
},
{