From f76f1f54ae386f680178f0706e75d9c7e1aa70f0 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 10 May 2019 22:17:13 +1000 Subject: [PATCH 1/4] Add 'variant' field to Part model - Display 'long_name' which is concatenation of name and variant --- InvenTree/part/forms.py | 1 + .../migrations/0020_auto_20190510_2022.py | 27 +++++++++++++++++ InvenTree/part/models.py | 29 ++++++++++++++----- InvenTree/part/serializers.py | 4 ++- .../part/templates/part/part_app_base.html | 2 +- InvenTree/part/templates/part/part_base.html | 7 +++-- .../part/templates/part/partial_delete.html | 4 +-- InvenTree/part/templates/part/supplier.html | 2 +- InvenTree/part/templates/part/track.html | 2 +- InvenTree/static/script/inventree/part.js | 8 ++++- InvenTree/templates/required_part_table.html | 2 +- 11 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 InvenTree/part/migrations/0020_auto_20190510_2022.py diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 1b2814ba52..1a3f8b6125 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -65,6 +65,7 @@ class EditPartForm(HelperForm): fields = [ 'category', 'name', + 'variant', 'description', 'IPN', 'URL', diff --git a/InvenTree/part/migrations/0020_auto_20190510_2022.py b/InvenTree/part/migrations/0020_auto_20190510_2022.py new file mode 100644 index 0000000000..8bf6db8f18 --- /dev/null +++ b/InvenTree/part/migrations/0020_auto_20190510_2022.py @@ -0,0 +1,27 @@ +# Generated by Django 2.2 on 2019-05-10 10:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0019_auto_20190508_2332'), + ] + + operations = [ + migrations.AddField( + model_name='part', + name='variant', + field=models.CharField(blank=True, help_text='Part variant or revision code', max_length=32), + ), + migrations.AlterField( + model_name='part', + name='name', + field=models.CharField(help_text='Part name', max_length=100), + ), + migrations.AlterUniqueTogether( + name='part', + unique_together={('name', 'variant')}, + ), + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 5a318c85b5..a349776979 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -124,6 +124,7 @@ class Part(models.Model): Attributes: name: Brief name for this part + variant: Optional variant number for this part - Must be unique for the part name description: Longer form description of the part category: The PartCategory to which this part belongs IPN: Internal part number (optional) @@ -142,6 +143,23 @@ class Part(models.Model): notes: Additional notes field for this part """ + class Meta: + verbose_name = "Part" + verbose_name_plural = "Parts" + unique_together = [ + ('name', 'variant') + ] + + def __str__(self): + return "{n} - {d}".format(n=self.long_name, d=self.description) + + @property + def long_name(self): + name = self.name + if self.variant: + name += " | " + self.variant + return name + def get_absolute_url(self): """ Return the web URL for viewing this part """ return reverse('part-detail', kwargs={'pk': self.id}) @@ -154,7 +172,9 @@ class Part(models.Model): else: return static('/img/blank_image.png') - name = models.CharField(max_length=100, unique=True, blank=False, help_text='Part name (must be unique)') + name = models.CharField(max_length=100, blank=False, help_text='Part name') + + variant = models.CharField(max_length=32, blank=True, help_text='Part variant or revision code') description = models.CharField(max_length=250, blank=False, help_text='Part description') @@ -228,9 +248,6 @@ class Part(models.Model): notes = models.TextField(blank=True) - def __str__(self): - return "{n} - {d}".format(n=self.name, d=self.description) - def format_barcode(self): """ Return a JSON string for formatting a barcode for this Part object """ @@ -243,10 +260,6 @@ class Part(models.Model): } ) - class Meta: - verbose_name = "Part" - verbose_name_plural = "Parts" - @property def category_path(self): if self.category: diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 97588650cb..8cc56daabb 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -41,9 +41,10 @@ class PartBriefSerializer(serializers.ModelSerializer): 'pk', 'url', 'name', - 'image_url', + 'variant', 'description', 'available_stock', + 'image_url', ] @@ -63,6 +64,7 @@ class PartSerializer(serializers.ModelSerializer): 'pk', 'url', # Link to the part detail page 'name', + 'variant', 'image_url', 'IPN', 'URL', # Link to an external URL (optional) diff --git a/InvenTree/part/templates/part/part_app_base.html b/InvenTree/part/templates/part/part_app_base.html index cb1fbdef90..ed3ecfb1b9 100644 --- a/InvenTree/part/templates/part/part_app_base.html +++ b/InvenTree/part/templates/part/part_app_base.html @@ -4,7 +4,7 @@ {% block page_title %} {% if part %} -InvenTree | Part - {{ part.name }} +InvenTree | Part - {{ part.long_name }} {% elif category %} InvenTree | Part Category - {{ category }} {% else %} diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index c73d8d5db7..d13495bc52 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -7,7 +7,7 @@
{% if part.active == False %}
- This part ({{ part.name }}) is not active: + This part ({{ part.long_name }}) is not active:
{% endif %}
@@ -24,8 +24,11 @@

- {{ part.name }} + {{ part.long_name }}

+ {% if part.variant %} +

Variant: {{ part.variant }}

+ {% endif %}

{{ part.description }}

diff --git a/InvenTree/part/templates/part/partial_delete.html b/InvenTree/part/templates/part/partial_delete.html index 8d60cfff70..e30be8444a 100644 --- a/InvenTree/part/templates/part/partial_delete.html +++ b/InvenTree/part/templates/part/partial_delete.html @@ -1,4 +1,4 @@ -Are you sure you want to delete part '{{ part.name }}'? +Are you sure you want to delete part '{{ part.long_name }}'? {% if part.used_in_count %}

This part is used in BOMs for {{ part.used_in_count }} other parts. If you delete this part, the BOMs for the following parts will be updated: @@ -30,5 +30,5 @@ Are you sure you want to delete part '{{ part.name }}'? {% endif %} {% if part.serials.all|length > 0 %} -

There are {{ part.serials.all|length }} unique parts tracked for '{{ part.name }}'. Deleting this part will permanently remove this tracking information.

+

There are {{ part.serials.all|length }} unique parts tracked for '{{ part.long_name }}'. Deleting this part will permanently remove this tracking information.

{% endif %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/supplier.html b/InvenTree/part/templates/part/supplier.html index 4999694651..5112dad913 100644 --- a/InvenTree/part/templates/part/supplier.html +++ b/InvenTree/part/templates/part/supplier.html @@ -48,7 +48,7 @@ $("#supplier-table").bootstrapTable({ sortable: true, search: true, - formatNoMatches: function() { return "No supplier parts available for {{ part.name }}"; }, + formatNoMatches: function() { return "No supplier parts available for {{ part.long_name }}"; }, queryParams: function(p) { return { part: {{ part.id }} diff --git a/InvenTree/part/templates/part/track.html b/InvenTree/part/templates/part/track.html index 01e174eef0..05f9d366d7 100644 --- a/InvenTree/part/templates/part/track.html +++ b/InvenTree/part/templates/part/track.html @@ -4,7 +4,7 @@ {% include 'part/tabs.html' with tab='track' %} -Part tracking for {{ part.name }} +Part tracking for {{ part.long_name }} diff --git a/InvenTree/static/script/inventree/part.js b/InvenTree/static/script/inventree/part.js index a991cb232c..82757b47bc 100644 --- a/InvenTree/static/script/inventree/part.js +++ b/InvenTree/static/script/inventree/part.js @@ -123,7 +123,13 @@ function loadPartTable(table, url, options={}) { title: 'Part', sortable: true, formatter: function(value, row, index, field) { - var display = imageHoverIcon(row.image_url) + renderLink(value, row.url); + var name = row.name; + + if (row.variant) { + name = name + " | " + row.variant; + } + + var display = imageHoverIcon(row.image_url) + renderLink(name, row.url); if (!row.active) { display = display + "INACTIVE"; } diff --git a/InvenTree/templates/required_part_table.html b/InvenTree/templates/required_part_table.html index 4ae1441f11..5d362e8f77 100644 --- a/InvenTree/templates/required_part_table.html +++ b/InvenTree/templates/required_part_table.html @@ -8,7 +8,7 @@ {% for part in parts %} - + From 68b273aae1720f9b8f4a7be34df2ebe20ad812e4 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 10 May 2019 22:18:56 +1000 Subject: [PATCH 2/4] Fixed some more part name displays --- InvenTree/part/templates/part/category_delete.html | 2 +- InvenTree/part/templates/part/detail.html | 6 +++--- InvenTree/part/templates/part/used_in.html | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/InvenTree/part/templates/part/category_delete.html b/InvenTree/part/templates/part/category_delete.html index 8b6d5618f3..c603637765 100644 --- a/InvenTree/part/templates/part/category_delete.html +++ b/InvenTree/part/templates/part/category_delete.html @@ -27,7 +27,7 @@ the top level 'Parts' category.

    {% for part in category.parts.all %} -
  • {{ part.name }} - {{ part.description }}
  • +
  • {{ part.long_name }} - {{ part.description }}
  • {% endfor %}
{% endif %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 419409a95d..3242316136 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -34,7 +34,7 @@
{{ part.name }}{{ part.long_name }} {{ part.description }} {{ part.total_stock }} {{ part.allocation_count }}
- + @@ -147,7 +147,7 @@ $('#activate-part').click(function() { showQuestionDialog( 'Activate Part?', - 'Are you sure you wish to reactivate {{ part.name }}?', + 'Are you sure you wish to reactivate {{ part.long_name }}?', { accept_text: 'Activate', accept: function() { @@ -169,7 +169,7 @@ $('#deactivate-part').click(function() { showQuestionDialog( 'Deactivate Part?', - `Are you sure you wish to deactivate {{ part.name }}?
+ `Are you sure you wish to deactivate {{ part.long_name }}?
`, { accept_text: 'Deactivate', diff --git a/InvenTree/part/templates/part/used_in.html b/InvenTree/part/templates/part/used_in.html index f1a055695e..f7272dfea6 100644 --- a/InvenTree/part/templates/part/used_in.html +++ b/InvenTree/part/templates/part/used_in.html @@ -27,7 +27,7 @@ $("#used-table").bootstrapTable({ sortable: true, search: true, - formatNoMatches: function() { return "{{ part.name }} is not used to make any other parts"; }, + formatNoMatches: function() { return "{{ part.long_name }} is not used to make any other parts"; }, queryParams: function(p) { return { sub_part: {{ part.id }} From 8ac180a9e3ac2511adfc2e785297dab26ca8ff8d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 10 May 2019 22:52:06 +1000 Subject: [PATCH 3/4] Add validator to part name - Check for 'illegal' characters - Mostly just as a test for validators! --- InvenTree/InvenTree/validators.py | 15 +++++++++++++++ .../migrations/0021_auto_20190510_2220.py | 19 +++++++++++++++++++ InvenTree/part/models.py | 5 ++++- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 InvenTree/InvenTree/validators.py create mode 100644 InvenTree/part/migrations/0021_auto_20190510_2220.py diff --git a/InvenTree/InvenTree/validators.py b/InvenTree/InvenTree/validators.py new file mode 100644 index 0000000000..c7fcadc5e2 --- /dev/null +++ b/InvenTree/InvenTree/validators.py @@ -0,0 +1,15 @@ +""" +Custom field validators for InvenTree +""" + +from django.core.exceptions import ValidationError +from django.utils.translation import gettext_lazy as _ + + +def validate_part_name(value): + # Prevent some illegal characters in part names + for c in ['/', '\\', '|', '#', '$']: + if c in str(value): + raise ValidationError( + _('Invalid character in part name') + ) \ No newline at end of file diff --git a/InvenTree/part/migrations/0021_auto_20190510_2220.py b/InvenTree/part/migrations/0021_auto_20190510_2220.py new file mode 100644 index 0000000000..294bd112ae --- /dev/null +++ b/InvenTree/part/migrations/0021_auto_20190510_2220.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2 on 2019-05-10 12:20 + +import InvenTree.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0020_auto_20190510_2022'), + ] + + operations = [ + migrations.AlterField( + model_name='part', + name='name', + field=models.CharField(help_text='Part name', max_length=100, validators=[InvenTree.validators.validate_part_name]), + ), + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index a349776979..c5e7e8d9c6 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -25,6 +25,7 @@ from django.db.models.signals import pre_delete from django.dispatch import receiver from InvenTree import helpers +from InvenTree import validators from InvenTree.models import InvenTreeTree from company.models import Company @@ -172,7 +173,9 @@ class Part(models.Model): else: return static('/img/blank_image.png') - name = models.CharField(max_length=100, blank=False, help_text='Part name') + name = models.CharField(max_length=100, blank=False, help_text='Part name', + validators=[validators.validate_part_name] + ) variant = models.CharField(max_length=32, blank=True, help_text='Part variant or revision code') From 7f1cdaf73f5d8e0f3d11c304a332adef4d408c31 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 10 May 2019 22:52:45 +1000 Subject: [PATCH 4/4] PEP --- InvenTree/InvenTree/validators.py | 2 +- InvenTree/part/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/InvenTree/validators.py b/InvenTree/InvenTree/validators.py index c7fcadc5e2..88da882e10 100644 --- a/InvenTree/InvenTree/validators.py +++ b/InvenTree/InvenTree/validators.py @@ -12,4 +12,4 @@ def validate_part_name(value): if c in str(value): raise ValidationError( _('Invalid character in part name') - ) \ No newline at end of file + ) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index c5e7e8d9c6..0318c11f57 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -177,7 +177,7 @@ class Part(models.Model): validators=[validators.validate_part_name] ) - variant = models.CharField(max_length=32, blank=True, help_text='Part variant or revision code') + variant = models.CharField(max_length=32, blank=True, help_text='Part variant or revision code') description = models.CharField(max_length=250, blank=False, help_text='Part description')
Part name{{ part.name }}{{ part.long_name }}
Description