From 8f1af0f5f98ac5a3110905c9b85706781e4fe030 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 23 Aug 2020 09:07:15 +1000 Subject: [PATCH 1/8] Add "enabled" field to Label class - Only list labels which are enabled - Allows labels to be hidden / disabled without being deleted --- InvenTree/label/admin.py | 2 +- .../migrations/0002_stockitemlabel_enabled.py | 18 ++++++++++++++++++ InvenTree/label/models.py | 6 ++++++ InvenTree/stock/views.py | 3 ++- 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 InvenTree/label/migrations/0002_stockitemlabel_enabled.py diff --git a/InvenTree/label/admin.py b/InvenTree/label/admin.py index bc03e122b6..71399efabb 100644 --- a/InvenTree/label/admin.py +++ b/InvenTree/label/admin.py @@ -8,7 +8,7 @@ from .models import StockItemLabel class StockItemLabelAdmin(admin.ModelAdmin): - list_display = ('name', 'description', 'label') + list_display = ('name', 'description', 'label', 'filters', 'enabled') admin.site.register(StockItemLabel, StockItemLabelAdmin) diff --git a/InvenTree/label/migrations/0002_stockitemlabel_enabled.py b/InvenTree/label/migrations/0002_stockitemlabel_enabled.py new file mode 100644 index 0000000000..684299e184 --- /dev/null +++ b/InvenTree/label/migrations/0002_stockitemlabel_enabled.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.7 on 2020-08-22 23:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('label', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='stockitemlabel', + name='enabled', + field=models.BooleanField(default=True, help_text='Label template is enabled', verbose_name='Enabled'), + ), + ] diff --git a/InvenTree/label/models.py b/InvenTree/label/models.py index 7d481327a9..49b07572a8 100644 --- a/InvenTree/label/models.py +++ b/InvenTree/label/models.py @@ -70,6 +70,12 @@ class LabelTemplate(models.Model): validators=[validateFilterString] ) + enabled = models.BooleanField( + default=True, + help_text=_('Label template is enabled'), + verbose_name=_('Enabled') + ) + def get_record_data(self, items): """ Return a list of dict objects, one for each item. diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 1c9b78a3f0..faad9db324 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -310,7 +310,8 @@ class StockItemSelectLabels(AjaxView): labels = [] - for label in StockItemLabel.objects.all(): + # Construct a list of StockItemLabel objects which are enabled, and the filters match the selected StockItem + for label in StockItemLabel.objects.filter(enabled=True): if label.matches_stock_item(item): labels.append(label) From 771b2117c407aa2dfb2436970df3b491410b16ec Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 23 Aug 2020 09:08:24 +1000 Subject: [PATCH 2/8] Remove duplicated function --- InvenTree/report/models.py | 55 ++------------------------------------ 1 file changed, 2 insertions(+), 53 deletions(-) diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index 697f5691d5..c85f8e0f57 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -16,6 +16,8 @@ from django.conf import settings from django.core.validators import FileExtensionValidator from django.core.exceptions import ValidationError +from InvenTree.helpers import validateFilterString + from django.utils.translation import gettext_lazy as _ from part import models as PartModels @@ -55,59 +57,6 @@ def rename_template(instance, filename): return os.path.join('report', 'report_template', instance.getSubdir(), filename) -def validateFilterString(value): - """ - Validate that a provided filter string looks like a list of comma-separated key=value pairs - - These should nominally match to a valid database filter based on the model being filtered. - - e.g. "category=6, IPN=12" - e.g. "part__name=widget" - - The ReportTemplate class uses the filter string to work out which items a given report applies to. - For example, an acceptance test report template might only apply to stock items with a given IPN, - so the string could be set to: - - filters = "IPN = ACME0001" - - Returns a map of key:value pairs - """ - - # Empty results map - results = {} - - value = str(value).strip() - - if not value or len(value) == 0: - return results - - groups = value.split(',') - - for group in groups: - group = group.strip() - - pair = group.split('=') - - if not len(pair) == 2: - raise ValidationError( - "Invalid group: {g}".format(g=group) - ) - - k, v = pair - - k = k.strip() - v = v.strip() - - if not k or not v: - raise ValidationError( - "Invalid group: {g}".format(g=group) - ) - - results[k] = v - - return results - - class WeasyprintReportMixin(WeasyTemplateResponseMixin): """ Class for rendering a HTML template to a PDF. From 116d966d2912524eedb4ef5d7e1ba9454fabd7de Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 23 Aug 2020 09:10:56 +1000 Subject: [PATCH 3/8] Delete "ReportTemplate" class --- InvenTree/report/admin.py | 4 +--- .../migrations/0002_delete_reporttemplate.py | 16 ++++++++++++++++ InvenTree/report/models.py | 9 --------- 3 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 InvenTree/report/migrations/0002_delete_reporttemplate.py diff --git a/InvenTree/report/admin.py b/InvenTree/report/admin.py index 4183e8ee83..9ec3c5c8f8 100644 --- a/InvenTree/report/admin.py +++ b/InvenTree/report/admin.py @@ -3,8 +3,7 @@ from __future__ import unicode_literals from django.contrib import admin -from .models import ReportTemplate, ReportAsset -from .models import TestReport +from .models import TestReport, ReportAsset class ReportTemplateAdmin(admin.ModelAdmin): @@ -17,6 +16,5 @@ class ReportAssetAdmin(admin.ModelAdmin): list_display = ('asset', 'description') -admin.site.register(ReportTemplate, ReportTemplateAdmin) admin.site.register(TestReport, ReportTemplateAdmin) admin.site.register(ReportAsset, ReportAssetAdmin) diff --git a/InvenTree/report/migrations/0002_delete_reporttemplate.py b/InvenTree/report/migrations/0002_delete_reporttemplate.py new file mode 100644 index 0000000000..7abfe72c59 --- /dev/null +++ b/InvenTree/report/migrations/0002_delete_reporttemplate.py @@ -0,0 +1,16 @@ +# Generated by Django 3.0.7 on 2020-08-22 23:10 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('report', '0001_initial'), + ] + + operations = [ + migrations.DeleteModel( + name='ReportTemplate', + ), + ] diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index c85f8e0f57..649c2d27cc 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -151,15 +151,6 @@ class ReportTemplateBase(models.Model): abstract = True -class ReportTemplate(ReportTemplateBase): - """ - A simple reporting template which is used to upload template files, - which can then be used in other concrete template classes. - """ - - pass - - class PartFilterMixin(models.Model): """ A model mixin used for matching a report type against a Part object. From b7ae95686e40ce36898a7a4cc31cdfa027657155 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 23 Aug 2020 20:51:41 +1000 Subject: [PATCH 4/8] Add field "enabled" to Report template --- InvenTree/report/admin.py | 2 +- .../migrations/0003_testreport_enabled.py | 18 ++++++++++++++++++ InvenTree/report/models.py | 6 ++++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 InvenTree/report/migrations/0003_testreport_enabled.py diff --git a/InvenTree/report/admin.py b/InvenTree/report/admin.py index 9ec3c5c8f8..8efac4ac14 100644 --- a/InvenTree/report/admin.py +++ b/InvenTree/report/admin.py @@ -8,7 +8,7 @@ from .models import TestReport, ReportAsset class ReportTemplateAdmin(admin.ModelAdmin): - list_display = ('name', 'description', 'template') + list_display = ('name', 'description', 'template', 'enabled') class ReportAssetAdmin(admin.ModelAdmin): diff --git a/InvenTree/report/migrations/0003_testreport_enabled.py b/InvenTree/report/migrations/0003_testreport_enabled.py new file mode 100644 index 0000000000..74de252435 --- /dev/null +++ b/InvenTree/report/migrations/0003_testreport_enabled.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.7 on 2020-08-23 10:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('report', '0002_delete_reporttemplate'), + ] + + operations = [ + migrations.AddField( + model_name='testreport', + name='enabled', + field=models.BooleanField(default=True, help_text='Report template is enabled', verbose_name='Enabled'), + ), + ] diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index 649c2d27cc..47d3b053ac 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -147,6 +147,12 @@ class ReportTemplateBase(models.Model): description = models.CharField(max_length=250, help_text=_("Report template description")) + enabled = models.BooleanField( + default=True, + help_text=_('Report template is enabled'), + verbose_name=_('Enabled') + ) + class Meta: abstract = True From c849f618d51e54e8eac5ed987f71c1ad2d3cd351 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 23 Aug 2020 21:03:29 +1000 Subject: [PATCH 5/8] Clean up implementation of test report matching --- InvenTree/part/models.py | 18 ------------------ InvenTree/report/models.py | 11 +++++++++++ InvenTree/stock/forms.py | 13 ++++++++++--- InvenTree/stock/templates/stock/item_base.html | 4 ---- .../stock/templates/stock/item_tests.html | 2 -- 5 files changed, 21 insertions(+), 27 deletions(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index dd126d5730..29a4f85c7c 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -399,24 +399,6 @@ class Part(MPTTModel): self.category = category self.save() - def get_test_report_templates(self): - """ - Return all the TestReport template objects which map to this Part. - """ - - templates = [] - - for report in ReportModels.TestReport.objects.all(): - if report.matches_part(self): - templates.append(report) - - return templates - - def has_test_report_templates(self): - """ Return True if this part has a TestReport defined """ - - return len(self.get_test_report_templates()) > 0 - def get_absolute_url(self): """ Return the web URL for viewing this part """ return reverse('part-detail', kwargs={'pk': self.id}) diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index 47d3b053ac..100ea87c75 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -202,6 +202,17 @@ class TestReport(ReportTemplateBase, PartFilterMixin): # Requires a stock_item object to be given to it before rendering stock_item = None + def matches_stock_item(self, item): + """ + Test if this report template matches a given StockItem objects + """ + + filters = validateFilterString(self.part_filters) + + items = StockItem.objects.filter(**filters) + + return items.exists() + def get_context_data(self, request): return { 'stock_item': self.stock_item, diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index 234da6d53b..97d028ec2b 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -15,6 +15,8 @@ from InvenTree.helpers import GetExportFormats from InvenTree.forms import HelperForm from InvenTree.fields import RoundingDecimalFormField +from report.models import TestReport + from .models import StockLocation, StockItem, StockItemTracking from .models import StockItemAttachment from .models import StockItemTestResult @@ -225,12 +227,17 @@ class TestReportFormatForm(HelperForm): self.fields['template'].choices = self.get_template_choices() def get_template_choices(self): - """ Available choices """ + """ + Generate a list of of TestReport options for the StockItem + """ choices = [] - for report in self.stock_item.part.get_test_report_templates(): - choices.append((report.pk, report)) + templates = TestReport.objects.filter(enabled=True) + + for template in templates: + if template.matches_stock_item(self.stock_item): + choices.append(template) return choices diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index 1b4171297e..bcc2087b25 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -124,11 +124,9 @@ InvenTree | {% trans "Stock Item" %} - {{ item }} {% endif %} - {% if item.part.has_test_report_templates %} - {% endif %} {% endblock %} @@ -303,7 +301,6 @@ $("#stock-serialize").click(function() { ); }); -{% if item.part.has_test_report_templates %} $("#stock-test-report").click(function() { launchModalForm( "{% url 'stock-item-test-report-select' item.id %}", @@ -312,7 +309,6 @@ $("#stock-test-report").click(function() { } ); }); -{% endif %} $("#print-label").click(function() { launchModalForm( diff --git a/InvenTree/stock/templates/stock/item_tests.html b/InvenTree/stock/templates/stock/item_tests.html index c79068349d..10bb0950e4 100644 --- a/InvenTree/stock/templates/stock/item_tests.html +++ b/InvenTree/stock/templates/stock/item_tests.html @@ -17,9 +17,7 @@ {% endif %} - {% if item.part.has_test_report_templates %} - {% endif %}
From ed5ad3c0478bd59de12aecfb05e86e6e08561e45 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 23 Aug 2020 21:05:54 +1000 Subject: [PATCH 6/8] Rename 'part_filters' field to 'filters' --- .../migrations/0004_auto_20200823_1104.py | 18 ++++++++++++++++++ InvenTree/report/models.py | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 InvenTree/report/migrations/0004_auto_20200823_1104.py diff --git a/InvenTree/report/migrations/0004_auto_20200823_1104.py b/InvenTree/report/migrations/0004_auto_20200823_1104.py new file mode 100644 index 0000000000..ab9e961ad9 --- /dev/null +++ b/InvenTree/report/migrations/0004_auto_20200823_1104.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.7 on 2020-08-23 11:04 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('report', '0003_testreport_enabled'), + ] + + operations = [ + migrations.RenameField( + model_name='testreport', + old_name='part_filters', + new_name='filters', + ), + ] diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index 100ea87c75..625ca5582a 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -183,7 +183,7 @@ class PartFilterMixin(models.Model): """ Return a map of filters to be used for Part filtering """ return validateFilterString(self.part_filters) - part_filters = models.CharField( + filters = models.CharField( blank=True, max_length=250, help_text=_("Part query filters (comma-separated list of key=value pairs)"), From 9a35293126336cb4c1906f65642e0e8b17e4c42b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 23 Aug 2020 21:08:41 +1000 Subject: [PATCH 7/8] Remove PartFilterMixin class --- InvenTree/report/admin.py | 2 +- InvenTree/report/models.py | 34 +++------------------------------- 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/InvenTree/report/admin.py b/InvenTree/report/admin.py index 8efac4ac14..7d6403f5d9 100644 --- a/InvenTree/report/admin.py +++ b/InvenTree/report/admin.py @@ -8,7 +8,7 @@ from .models import TestReport, ReportAsset class ReportTemplateAdmin(admin.ModelAdmin): - list_display = ('name', 'description', 'template', 'enabled') + list_display = ('name', 'description', 'template', 'filters', 'enabled') class ReportAssetAdmin(admin.ModelAdmin): diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index 625ca5582a..66117f05ed 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -153,36 +153,6 @@ class ReportTemplateBase(models.Model): verbose_name=_('Enabled') ) - class Meta: - abstract = True - - -class PartFilterMixin(models.Model): - """ - A model mixin used for matching a report type against a Part object. - Used to assign a report to a given part using custom filters. - """ - - class Meta: - abstract = True - - def matches_part(self, part): - """ - Test if this report matches a given part. - """ - - filters = self.get_part_filters() - - parts = PartModels.Part.objects.filter(**filters) - - parts = parts.filter(pk=part.pk) - - return parts.exists() - - def get_part_filters(self): - """ Return a map of filters to be used for Part filtering """ - return validateFilterString(self.part_filters) - filters = models.CharField( blank=True, max_length=250, @@ -190,8 +160,10 @@ class PartFilterMixin(models.Model): validators=[validateFilterString] ) + class Meta: + abstract = True -class TestReport(ReportTemplateBase, PartFilterMixin): +class TestReport(ReportTemplateBase): """ Render a TestReport against a StockItem object. """ From ca1985e11abf7b520b24dc0b4235d8d80c373bec Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 23 Aug 2020 21:10:45 +1000 Subject: [PATCH 8/8] PEP fixes --- InvenTree/part/models.py | 1 - InvenTree/report/models.py | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 29a4f85c7c..239d8fabdb 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -41,7 +41,6 @@ from InvenTree.helpers import decimal2string, normalize from InvenTree.status_codes import BuildStatus, PurchaseOrderStatus -from report import models as ReportModels from build import models as BuildModels from order import models as OrderModels from company.models import SupplierPart diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index 66117f05ed..05507099a7 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -16,12 +16,12 @@ from django.conf import settings from django.core.validators import FileExtensionValidator from django.core.exceptions import ValidationError +from stock.models import StockItem + from InvenTree.helpers import validateFilterString from django.utils.translation import gettext_lazy as _ -from part import models as PartModels - try: from django_weasyprint import WeasyTemplateResponseMixin except OSError as err: @@ -163,6 +163,7 @@ class ReportTemplateBase(models.Model): class Meta: abstract = True + class TestReport(ReportTemplateBase): """ Render a TestReport against a StockItem object.