From 2f6357b1369bd8bbda6380b90fd252cb62648ab1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 12:31:43 +1000 Subject: [PATCH 01/16] Add PartParameter table --- .../part/migrations/0014_partparameter.py | 23 +++++++++++++++++++ InvenTree/part/models.py | 22 ++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 InvenTree/part/migrations/0014_partparameter.py diff --git a/InvenTree/part/migrations/0014_partparameter.py b/InvenTree/part/migrations/0014_partparameter.py new file mode 100644 index 0000000000..a1eef38ec6 --- /dev/null +++ b/InvenTree/part/migrations/0014_partparameter.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.4 on 2019-08-20 02:30 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0013_auto_20190628_0951'), + ] + + operations = [ + migrations.CreateModel( + name='PartParameter', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(help_text='Parameter Name', max_length=100)), + ('data', models.CharField(help_text='Parameter Value', max_length=100)), + ('part', models.ForeignKey(help_text='Parent Part', on_delete=django.db.models.deletion.CASCADE, related_name='parameters', to='part.Part')), + ], + ), + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 2e9e748e99..95a36f4804 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1028,6 +1028,28 @@ class PartStar(models.Model): unique_together = ['part', 'user'] +class PartParameter(models.Model): + """ A PartParameter provides key:value pairs for extra + parameters fields/values to be added to a Part. + This allows users to arbitrarily assign data fields to a Part + beyond the built-in attributes. + + Attributes: + part: Link to a Part object + name: The name (key) of the Parameter [string] + data: The data (value) of the Parameter [string] + """ + + part = models.ForeignKey(Part, on_delete=models.CASCADE, + related_name='parameters', + help_text='Parent Part', + ) + + name = models.CharField(max_length=100, help_text='Parameter Name') + + data = models.CharField(max_length=100, help_text='Parameter Value') + + class BomItem(models.Model): """ A BomItem links a part to its component items. A part can have a BOM (bill of materials) which defines From 1cd0051316bcd2dae9e78d276a1d40716f9ada2f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 12:43:12 +1000 Subject: [PATCH 02/16] Add page to display part parameters --- InvenTree/part/templates/part/params.html | 28 +++++++++++++++++++++++ InvenTree/part/urls.py | 1 + 2 files changed, 29 insertions(+) create mode 100644 InvenTree/part/templates/part/params.html diff --git a/InvenTree/part/templates/part/params.html b/InvenTree/part/templates/part/params.html new file mode 100644 index 0000000000..22161f9f5f --- /dev/null +++ b/InvenTree/part/templates/part/params.html @@ -0,0 +1,28 @@ +{% extends "part/part_base.html" %} +{% load static %} +{% block details %} + +{% include "part/tabs.html" with tab='params' %} + +

Part Parameters

+
+ + + + + + + {% for param in part.get_parameters %} + + + + + {% endfor %} +
NameValue
{{ param.name }}{{ param.data }}
+ +{% endblock %} + +{% block js_ready %} +{{ block.super }} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 3ec99e7255..64eebd6dc1 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -29,6 +29,7 @@ part_detail_urls = [ url(r'^bom-upload/?', views.BomUpload.as_view(), name='upload-bom'), + url(r'^params/', views.PartDetail.as_view(template_name='part/params.html'), name='part-params'), url(r'^variants/?', views.PartDetail.as_view(template_name='part/variants.html'), name='part-variants'), url(r'^stock/?', views.PartDetail.as_view(template_name='part/stock.html'), name='part-stock'), url(r'^allocation/?', views.PartDetail.as_view(template_name='part/allocation.html'), name='part-allocation'), From 0955166fae36d6c410d79ad2ddddbe45b22e2d95 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 12:43:23 +1000 Subject: [PATCH 03/16] Add admin interface for PartParameter --- InvenTree/part/admin.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/InvenTree/part/admin.py b/InvenTree/part/admin.py index 136d486b0b..02b7ea8c2b 100644 --- a/InvenTree/part/admin.py +++ b/InvenTree/part/admin.py @@ -4,6 +4,7 @@ from import_export.admin import ImportExportModelAdmin from .models import PartCategory, Part from .models import PartAttachment, PartStar from .models import BomItem +from .models import PartParameter class PartAdmin(ImportExportModelAdmin): @@ -33,14 +34,15 @@ class BomItemAdmin(ImportExportModelAdmin): """ class ParameterTemplateAdmin(admin.ModelAdmin): list_display = ('name', 'units', 'format') - +""" class ParameterAdmin(admin.ModelAdmin): - list_display = ('part', 'template', 'value') -""" + list_display = ('part', 'name', 'data') + admin.site.register(Part, PartAdmin) admin.site.register(PartCategory, PartCategoryAdmin) admin.site.register(PartAttachment, PartAttachmentAdmin) admin.site.register(PartStar, PartStarAdmin) admin.site.register(BomItem, BomItemAdmin) +admin.site.register(PartParameter, ParameterAdmin) From 6393ddad53542da6febe708d1fcc02e63d865b17 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 12:44:00 +1000 Subject: [PATCH 04/16] Add param tab to Part detail view --- InvenTree/part/models.py | 5 +++++ InvenTree/part/templates/part/tabs.html | 3 +++ 2 files changed, 8 insertions(+) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 95a36f4804..f1e78f502d 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -971,6 +971,11 @@ class Part(models.Model): return sum([part.on_order() for part in self.supplier_parts.all().prefetch_related('purchase_order_line_items')]) + def get_parameters(self): + """ Return all parameters for this part, ordered by name """ + + return self.parameters.order_by('name') + def attach_file(instance, filename): """ Function for storing a file for a PartAttachment diff --git a/InvenTree/part/templates/part/tabs.html b/InvenTree/part/templates/part/tabs.html index aa7a9fa885..86b7986b00 100644 --- a/InvenTree/part/templates/part/tabs.html +++ b/InvenTree/part/templates/part/tabs.html @@ -2,6 +2,9 @@ Details + + Parameters {{ part.parameters.count }} + {% if part.is_template %} Variants {{ part.variants.count }} From e6819b5396fc429eb7235be871a45d3fc03b5665 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 13:02:00 +1000 Subject: [PATCH 05/16] Change model - add PartParameterTemplate --- InvenTree/part/admin.py | 10 ++--- .../migrations/0015_auto_20190820_0251.py | 37 +++++++++++++++ .../migrations/0016_auto_20190820_0257.py | 17 +++++++ InvenTree/part/models.py | 45 ++++++++++++++++--- 4 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 InvenTree/part/migrations/0015_auto_20190820_0251.py create mode 100644 InvenTree/part/migrations/0016_auto_20190820_0257.py diff --git a/InvenTree/part/admin.py b/InvenTree/part/admin.py index 02b7ea8c2b..4de8278bec 100644 --- a/InvenTree/part/admin.py +++ b/InvenTree/part/admin.py @@ -4,7 +4,7 @@ from import_export.admin import ImportExportModelAdmin from .models import PartCategory, Part from .models import PartAttachment, PartStar from .models import BomItem -from .models import PartParameter +from .models import PartParameterTemplate, PartParameter class PartAdmin(ImportExportModelAdmin): @@ -31,13 +31,12 @@ class BomItemAdmin(ImportExportModelAdmin): list_display = ('part', 'sub_part', 'quantity') -""" class ParameterTemplateAdmin(admin.ModelAdmin): - list_display = ('name', 'units', 'format') -""" + list_display = ('name', 'units') + class ParameterAdmin(admin.ModelAdmin): - list_display = ('part', 'name', 'data') + list_display = ('part', 'template', 'data') admin.site.register(Part, PartAdmin) @@ -45,4 +44,5 @@ admin.site.register(PartCategory, PartCategoryAdmin) admin.site.register(PartAttachment, PartAttachmentAdmin) admin.site.register(PartStar, PartStarAdmin) admin.site.register(BomItem, BomItemAdmin) +admin.site.register(PartParameterTemplate, ParameterTemplateAdmin) admin.site.register(PartParameter, ParameterAdmin) diff --git a/InvenTree/part/migrations/0015_auto_20190820_0251.py b/InvenTree/part/migrations/0015_auto_20190820_0251.py new file mode 100644 index 0000000000..b981358519 --- /dev/null +++ b/InvenTree/part/migrations/0015_auto_20190820_0251.py @@ -0,0 +1,37 @@ +# Generated by Django 2.2.4 on 2019-08-20 02:51 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0014_partparameter'), + ] + + operations = [ + migrations.CreateModel( + name='PartParameterTemplate', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(help_text='Parameter Name', max_length=100)), + ('units', models.CharField(blank=True, help_text='Parameter Units', max_length=25)), + ], + ), + migrations.RemoveField( + model_name='partparameter', + name='name', + ), + migrations.AlterField( + model_name='partparameter', + name='data', + field=models.CharField(help_text='Parameter Value', max_length=500), + ), + migrations.AddField( + model_name='partparameter', + name='template', + field=models.ForeignKey(default=1, help_text='Parameter Template', on_delete=django.db.models.deletion.CASCADE, related_name='instances', to='part.PartParameterTemplate'), + preserve_default=False, + ), + ] diff --git a/InvenTree/part/migrations/0016_auto_20190820_0257.py b/InvenTree/part/migrations/0016_auto_20190820_0257.py new file mode 100644 index 0000000000..0399129078 --- /dev/null +++ b/InvenTree/part/migrations/0016_auto_20190820_0257.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.4 on 2019-08-20 02:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0015_auto_20190820_0251'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='partparameter', + unique_together={('part', 'template')}, + ), + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index f1e78f502d..0e234400f4 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1033,26 +1033,61 @@ class PartStar(models.Model): unique_together = ['part', 'user'] -class PartParameter(models.Model): - """ A PartParameter provides key:value pairs for extra +class PartParameterTemplate(models.Model): + """ A PartParameterTemplate provides a template for key:value pairs for extra parameters fields/values to be added to a Part. This allows users to arbitrarily assign data fields to a Part beyond the built-in attributes. Attributes: - part: Link to a Part object name: The name (key) of the Parameter [string] + units: The units of the Parameter [string] + """ + + def __str__(self): + s = str(self.name) + if self.units: + s += " ({units})".format(units=self.units) + return s + + + name = models.CharField(max_length=100, help_text='Parameter Name') + + units = models.CharField(max_length=25, help_text='Parameter Units', blank=True) + + +class PartParameter(models.Model): + """ A PartParameter is a specific instance of a PartParameterTemplate. + + Attributes: + part: Reference to a single Part object + template: Reference to a single PartParameterTemplate object data: The data (value) of the Parameter [string] """ + def __str__(self): + return "{part} : {param} = {data}{units}".format( + part=str(self.part), + param=str(self.template.name), + data=str(self.data), + units=str(self.template.units) + ) + + class Meta: + # Prevent multiple instances of a parameter for a single part + unique_together = ('part', 'template') + part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='parameters', help_text='Parent Part', ) - name = models.CharField(max_length=100, help_text='Parameter Name') + template = models.ForeignKey(PartParameterTemplate, on_delete=models.CASCADE, + related_name='instances', + help_text='Parameter Template' + ) - data = models.CharField(max_length=100, help_text='Parameter Value') + data = models.CharField(max_length=500, help_text='Parameter Value') class BomItem(models.Model): From a228b38e5d15fe7425e72482e7a4531e30be9ed8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 13:03:36 +1000 Subject: [PATCH 06/16] Fix parameter lookup --- InvenTree/part/models.py | 2 +- InvenTree/part/templates/part/params.html | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 0e234400f4..ab9877e42c 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -974,7 +974,7 @@ class Part(models.Model): def get_parameters(self): """ Return all parameters for this part, ordered by name """ - return self.parameters.order_by('name') + return self.parameters.order_by('template__name') def attach_file(instance, filename): diff --git a/InvenTree/part/templates/part/params.html b/InvenTree/part/templates/part/params.html index 22161f9f5f..8719246223 100644 --- a/InvenTree/part/templates/part/params.html +++ b/InvenTree/part/templates/part/params.html @@ -7,19 +7,23 @@

Part Parameters


- - - - - + +
NameValue
+ + + + + {% for param in part.get_parameters %} - + + {% endfor %}
NameValueUnits
{{ param.name }}{{ param.template.name }} {{ param.data }}{{ param.template.units }}
- + + {% endblock %} {% block js_ready %} From db834802e372f3f136044f90d58617f3c3e5cb6e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 13:08:06 +1000 Subject: [PATCH 07/16] Add uniqueness check for PartParameterTemplate name field - Case insensitive --- InvenTree/part/models.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index ab9877e42c..f1a1747e44 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1050,6 +1050,21 @@ class PartParameterTemplate(models.Model): s += " ({units})".format(units=self.units) return s + def validate_unique(self, exclude=None): + """ Ensure that PartParameterTemplates cannot be created with the same name. + This test should be case-insensitive (which the unique caveat does not cover). + """ + + super().validate_unique(exclude) + + try: + others = PartParameterTemplate.objects.exclude(id=self.id).filter(name__iexact=self.name) + + if others.exists(): + msg = _("Parameter template name must be unique") + raise ValidationError({"name": msg}) + except PartParameterTemplate.DoesNotExist: + pass name = models.CharField(max_length=100, help_text='Parameter Name') From c68c79ea43b25e9bd1d60c219e51d97b366a54a2 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 14:14:21 +1000 Subject: [PATCH 08/16] Create view / form / URL for PartParameter creation --- InvenTree/part/forms.py | 13 +++++++ InvenTree/part/models.py | 5 +++ InvenTree/part/templates/part/params.html | 46 ++++++++++++++++------- InvenTree/part/urls.py | 7 ++++ InvenTree/part/views.py | 10 +++++ 5 files changed, 68 insertions(+), 13 deletions(-) diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 0d82183a93..c26d670496 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -11,6 +11,7 @@ from django import forms from .models import Part, PartCategory, PartAttachment from .models import BomItem +from .models import PartParameterTemplate, PartParameter class PartImageForm(HelperForm): @@ -98,6 +99,18 @@ class EditPartForm(HelperForm): ] +class EditPartParameterForm(HelperForm): + """ Form for editing a PartParameter object """ + + class Meta: + model = PartParameter + fields = [ + 'part', + 'template', + 'data' + ] + + class EditCategoryForm(HelperForm): """ Form for editing a PartCategory object """ diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index f1a1747e44..aa2aed98a6 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1066,6 +1066,11 @@ class PartParameterTemplate(models.Model): except PartParameterTemplate.DoesNotExist: pass + @property + def instance_count(self): + """ Return the number of instances of this Parameter Template """ + return self.instances.count() + name = models.CharField(max_length=100, help_text='Parameter Name') units = models.CharField(max_length=25, help_text='Parameter Units', blank=True) diff --git a/InvenTree/part/templates/part/params.html b/InvenTree/part/templates/part/params.html index 8719246223..954541feb2 100644 --- a/InvenTree/part/templates/part/params.html +++ b/InvenTree/part/templates/part/params.html @@ -7,20 +7,29 @@

Part Parameters


+
+
+ +
+
- - - - - - - {% for param in part.get_parameters %} - - - - - - {% endfor %} +
NameValueUnits
{{ param.template.name }}{{ param.data }}{{ param.template.units }}
+ + + + + + + + + {% for param in part.get_parameters %} + + + + + + {% endfor %} +
NameValueUnits
{{ param.template.name }}{{ param.data }}{{ param.template.units }}
@@ -29,4 +38,15 @@ {% block js_ready %} {{ block.super }} + $('#param-table').bootstrapTable({ + search: true, + sortable: true, + }); + + $('#param-create').click(function() { + launchModalForm("{% url 'part-param-create' %}?part={{ part.id }}", { + reload: true, + }); + }); + {% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 64eebd6dc1..f892cc566b 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -18,6 +18,10 @@ part_attachment_urls = [ url(r'^(?P\d+)/delete/?', views.PartAttachmentDelete.as_view(), name='part-attachment-delete'), ] +part_parameter_urls = [ + url('^new/?', views.PartParameterCreate.as_view(), name='part-param-create'), +] + part_detail_urls = [ url(r'^edit/?', views.PartEdit.as_view(), name='part-edit'), url(r'^delete/?', views.PartDelete.as_view(), name='part-delete'), @@ -91,6 +95,9 @@ part_urls = [ # Part attachments url(r'^attachment/', include(part_attachment_urls)), + # Part parameters + url(r'^parameter/', include(part_parameter_urls)), + # Change category for multiple parts url(r'^set-category/?', views.PartSetCategory.as_view(), name='part-set-category'), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 3b475cec7b..a6e1fe00aa 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -19,6 +19,7 @@ import tablib from fuzzywuzzy import fuzz from .models import PartCategory, Part, PartAttachment +from .models import PartParameterTemplate, PartParameter from .models import BomItem from .models import match_part_names @@ -1396,6 +1397,15 @@ class PartPricing(AjaxView): return self.renderJsonResponse(request, self.form_class(), data=data, context=self.get_pricing(quantity)) +class PartParameterCreate(AjaxCreateView): + """ View for creating a new PartParameter """ + + model = PartParameter + form_class = part_forms.EditPartParameterForm + ajax_form_title = 'Create Part Parameter' + + + class CategoryDetail(DetailView): """ Detail view for PartCategory """ model = PartCategory From 15a42878db0e3e360c36294952e5121fd481730c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 14:28:15 +1000 Subject: [PATCH 09/16] Improved view for creating a new part parameter - Hide the Part input - Reduce options based on parameters that already exist! --- InvenTree/part/urls.py | 2 +- InvenTree/part/views.py | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index f892cc566b..86162b4ec2 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -19,7 +19,7 @@ part_attachment_urls = [ ] part_parameter_urls = [ - url('^new/?', views.PartParameterCreate.as_view(), name='part-param-create'), + url('^new/', views.PartParameterCreate.as_view(), name='part-param-create'), ] part_detail_urls = [ diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index a6e1fe00aa..4e30944058 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -1404,6 +1404,47 @@ class PartParameterCreate(AjaxCreateView): form_class = part_forms.EditPartParameterForm ajax_form_title = 'Create Part Parameter' + def get_initial(self): + + initials = {} + + part_id = self.request.GET.get('part', None) + + if part_id: + try: + initials['part'] = Part.objects.get(pk=part_id) + except (Part.DoesNotExist, ValueError): + pass + + return initials + + def get_form(self): + """ Return the form object. + + - Hide the 'Part' field (specified in URL) + - Limit the 'Template' options (to avoid duplicates) + """ + + form = super().get_form() + + part_id = self.request.GET.get('part', None) + + if part_id: + try: + part = Part.objects.get(pk=part_id) + + form.fields['part'].widget = HiddenInput() + + query = form.fields['template'].queryset + + query = query.exclude(id__in=[param.template.id for param in part.parameters.all()]) + + form.fields['template'].queryset = query + + except (Part.DoesNotExist, ValueError): + pass + + return form class CategoryDetail(DetailView): From 307a04da58d94a21c99dad0b771212888e268017 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 14:33:18 +1000 Subject: [PATCH 10/16] Add View/Form for creating a new PartParameterTemplate --- InvenTree/part/forms.py | 11 +++++++++++ InvenTree/part/templates/part/params.html | 8 +++++++- InvenTree/part/urls.py | 4 ++++ InvenTree/part/views.py | 8 ++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index c26d670496..bbb136b28d 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -99,6 +99,17 @@ class EditPartForm(HelperForm): ] +class EditPartParameterTemplateForm(HelperForm): + """ Form for editing a PartParameterTemplate object """ + + class Meta: + model = PartParameterTemplate + fields = [ + 'name', + 'units' + ] + + class EditPartParameterForm(HelperForm): """ Form for editing a PartParameter object """ diff --git a/InvenTree/part/templates/part/params.html b/InvenTree/part/templates/part/params.html index 954541feb2..50098ed6e6 100644 --- a/InvenTree/part/templates/part/params.html +++ b/InvenTree/part/templates/part/params.html @@ -45,7 +45,13 @@ $('#param-create').click(function() { launchModalForm("{% url 'part-param-create' %}?part={{ part.id }}", { - reload: true, + reload: true, + secondary: [{ + field: 'template', + label: 'New Template', + title: 'Create New Parameter Template', + url: "{% url 'part-param-template-create' %}" + }], }); }); diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 86162b4ec2..79a0689ee8 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -19,7 +19,11 @@ part_attachment_urls = [ ] part_parameter_urls = [ + + url('^template/new/', views.PartParameterTemplateCreate.as_view(), name='part-param-template-create'), + url('^new/', views.PartParameterCreate.as_view(), name='part-param-create'), + ] part_detail_urls = [ diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 4e30944058..2026b09de7 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -1397,6 +1397,14 @@ class PartPricing(AjaxView): return self.renderJsonResponse(request, self.form_class(), data=data, context=self.get_pricing(quantity)) +class PartParameterTemplateCreate(AjaxCreateView): + """ View for creating a new PartParameterTemplate """ + + model = PartParameterTemplate + form_class = part_forms.EditPartParameterTemplateForm + ajax_form_title = 'Create Part Parameter Template' + + class PartParameterCreate(AjaxCreateView): """ View for creating a new PartParameter """ From 9630c909247631f36e34b8e471459f9f75f9df44 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 18:01:20 +1000 Subject: [PATCH 11/16] Add buttons to edit/delete parameters --- InvenTree/part/templates/part/params.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/templates/part/params.html b/InvenTree/part/templates/part/params.html index 50098ed6e6..0419fe6934 100644 --- a/InvenTree/part/templates/part/params.html +++ b/InvenTree/part/templates/part/params.html @@ -26,7 +26,13 @@ {{ param.template.name }} {{ param.data }} - {{ param.template.units }} + + {{ param.template.units }} +
+ + +
+ {% endfor %} From e77aeec2ce7ac154d2bc39ffbe2a99e22c5c11e8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2019 18:04:22 +1000 Subject: [PATCH 12/16] Change to ImportExport model admin --- InvenTree/part/admin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/part/admin.py b/InvenTree/part/admin.py index 4de8278bec..e7489c9810 100644 --- a/InvenTree/part/admin.py +++ b/InvenTree/part/admin.py @@ -31,11 +31,11 @@ class BomItemAdmin(ImportExportModelAdmin): list_display = ('part', 'sub_part', 'quantity') -class ParameterTemplateAdmin(admin.ModelAdmin): +class ParameterTemplateAdmin(ImportExportModelAdmin): list_display = ('name', 'units') -class ParameterAdmin(admin.ModelAdmin): +class ParameterAdmin(ImportExportModelAdmin): list_display = ('part', 'template', 'data') From 51e4bdd8219a03ae95c7b0e288023b59051d291a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 21 Aug 2019 13:11:19 +1000 Subject: [PATCH 13/16] URL / view for editing a PartParameter --- InvenTree/part/urls.py | 1 + InvenTree/part/views.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 79a0689ee8..98e7227ac7 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -23,6 +23,7 @@ part_parameter_urls = [ url('^template/new/', views.PartParameterTemplateCreate.as_view(), name='part-param-template-create'), url('^new/', views.PartParameterCreate.as_view(), name='part-param-create'), + url('^(?P\d+)/edit/', views.PartParameterEdit.as_view(), name='part-param-edit'), ] diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 2026b09de7..fcb0c889e2 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -1455,6 +1455,20 @@ class PartParameterCreate(AjaxCreateView): return form +class PartParameterEdit(AjaxUpdateView): + """ View for editing a PartParameter """ + + model = PartParameter + form_class = part_forms.EditPartParameterForm + ajax_form_title = 'Edit Part Parameter' + + def get_form(self): + + form = super().get_form() + + return form + + class CategoryDetail(DetailView): """ Detail view for PartCategory """ model = PartCategory From 586a46175d37fa500db9f74d1991d053b8529e26 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 28 Aug 2019 19:39:47 +1000 Subject: [PATCH 14/16] Add modals for editing or deleting part parameters --- .../part/templates/part/param_delete.html | 5 +++++ InvenTree/part/templates/part/params.html | 20 +++++++++++++++++-- InvenTree/part/urls.py | 1 + InvenTree/part/views.py | 8 ++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 InvenTree/part/templates/part/param_delete.html diff --git a/InvenTree/part/templates/part/param_delete.html b/InvenTree/part/templates/part/param_delete.html new file mode 100644 index 0000000000..efb8ca3c26 --- /dev/null +++ b/InvenTree/part/templates/part/param_delete.html @@ -0,0 +1,5 @@ +{% extends "modal_delete_form.html" %} + +{% block pre_form_content %} +Are you sure you want to remove this parameter? +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/params.html b/InvenTree/part/templates/part/params.html index 0419fe6934..1ccb9d4da6 100644 --- a/InvenTree/part/templates/part/params.html +++ b/InvenTree/part/templates/part/params.html @@ -29,8 +29,8 @@ {{ param.template.units }}
- - + +
@@ -61,4 +61,20 @@ }); }); + $('.param-edit').click(function() { + var button = $(this); + + launchModalForm(button.attr('url'), { + reload: true, + }); + }); + + $('.param-delete').click(function() { + var button = $(this); + + launchModalForm(button.attr('url'), { + reload: true, + }); + }); + {% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 98e7227ac7..d1fd1d59fc 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -24,6 +24,7 @@ part_parameter_urls = [ url('^new/', views.PartParameterCreate.as_view(), name='part-param-create'), url('^(?P\d+)/edit/', views.PartParameterEdit.as_view(), name='part-param-edit'), + url('^(?P\d+)/delete/', views.PartParameterDelete.as_view(), name='part-param-delete'), ] diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index fcb0c889e2..cc1300238e 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -1469,6 +1469,14 @@ class PartParameterEdit(AjaxUpdateView): return form +class PartParameterDelete(AjaxDeleteView): + """ View for deleting a PartParameter """ + + model = PartParameter + ajax_template_name = 'part/param_delete.html' + ajax_form_title = 'Delete Part Parameter' + + class CategoryDetail(DetailView): """ Detail view for PartCategory """ model = PartCategory From f94be408575d003f45dcf183192cb948b5c51fb8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 28 Aug 2019 19:44:02 +1000 Subject: [PATCH 15/16] Style fixes --- InvenTree/part/models.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index aa2aed98a6..cbdf1e4ba5 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1034,7 +1034,8 @@ class PartStar(models.Model): class PartParameterTemplate(models.Model): - """ A PartParameterTemplate provides a template for key:value pairs for extra + """ + A PartParameterTemplate provides a template for key:value pairs for extra parameters fields/values to be added to a Part. This allows users to arbitrarily assign data fields to a Part beyond the built-in attributes. @@ -1077,7 +1078,8 @@ class PartParameterTemplate(models.Model): class PartParameter(models.Model): - """ A PartParameter is a specific instance of a PartParameterTemplate. + """ + A PartParameter is a specific instance of a PartParameterTemplate. It assigns a particular parameter pair to a part. Attributes: part: Reference to a single Part object @@ -1098,14 +1100,9 @@ class PartParameter(models.Model): unique_together = ('part', 'template') part = models.ForeignKey(Part, on_delete=models.CASCADE, - related_name='parameters', - help_text='Parent Part', - ) + related_name='parameters', help_text='Parent Part') - template = models.ForeignKey(PartParameterTemplate, on_delete=models.CASCADE, - related_name='instances', - help_text='Parameter Template' - ) + template = models.ForeignKey(PartParameterTemplate, on_delete=models.CASCADE, related_name='instances', help_text='Parameter Template') data = models.CharField(max_length=500, help_text='Parameter Value') From d5ad53c788067d8fc04715e48195109ba1edd28f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 28 Aug 2019 19:44:46 +1000 Subject: [PATCH 16/16] Add docstring --- InvenTree/part/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index cbdf1e4ba5..382eccdf07 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1088,6 +1088,7 @@ class PartParameter(models.Model): """ def __str__(self): + # String representation of a PartParameter (used in the admin interface) return "{part} : {param} = {data}{units}".format( part=str(self.part), param=str(self.template.name),