From d5119e1affc5ce39b615983131e2865004b48aa3 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 20 Jun 2019 21:28:00 +1000 Subject: [PATCH 1/4] Replace some cog icons --- .../company/templates/company/company_base.html | 15 +++++++++++++-- InvenTree/part/templates/part/category.html | 2 +- InvenTree/stock/templates/stock/item.html | 2 +- InvenTree/stock/templates/stock/location.html | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/InvenTree/company/templates/company/company_base.html b/InvenTree/company/templates/company/company_base.html index 61751fe0f4..1063f967f5 100644 --- a/InvenTree/company/templates/company/company_base.html +++ b/InvenTree/company/templates/company/company_base.html @@ -26,12 +26,12 @@ InvenTree | Company - {{ company.name }}

{{ company.description }}

{% if company.is_supplier %} - {% endif %} {% if category %} {% endif %} "; - var bDelt = ""; + var bEdit = ""; + var bDelt = ""; return "
" + bEdit + bDelt + "
"; } From 8328e7e13c6bd4c1b1624f58385186b21f56b4a4 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 20 Jun 2019 21:37:25 +1000 Subject: [PATCH 3/4] Improve uniqueness checking for Part --- .../migrations/0010_auto_20190620_2135.py | 19 ++++++++++++++ InvenTree/part/models.py | 26 ++++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 InvenTree/part/migrations/0010_auto_20190620_2135.py diff --git a/InvenTree/part/migrations/0010_auto_20190620_2135.py b/InvenTree/part/migrations/0010_auto_20190620_2135.py new file mode 100644 index 0000000000..2033e2870f --- /dev/null +++ b/InvenTree/part/migrations/0010_auto_20190620_2135.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.2 on 2019-06-20 11:35 + +import InvenTree.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0009_part_virtual'), + ] + + 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 92acce5026..f77e2d94f4 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -203,6 +203,7 @@ class Part(models.Model): description: Longer form description of the part keywords: Optional keywords for improving part search results IPN: Internal part number (optional) + revision: Part revision is_template: If True, this part is a 'template' part and cannot be instantiated as a StockItem URL: Link to an external page with more information about this part (e.g. internal Wiki) image: Image of this part @@ -260,13 +261,30 @@ class Part(models.Model): return static('/img/blank_image.png') def validate_unique(self, exclude=None): + """ Validate that a part is 'unique'. + Uniqueness is checked across the following (case insensitive) fields: + + * Name + * IPN + * Revision + + e.g. there can exist multiple parts with the same name, but only if + they have a different revision or internal part number. + + """ super().validate_unique(exclude) # Part name uniqueness should be case insensitive try: - if Part.objects.filter(name__iexact=self.name).exclude(id=self.id).exists(): + parts = Part.objects.exclude(id=self.id).filter( + name__iexact=self.name, + IPN__iexact=self.IPN) + + if parts.exists(): + msg = _("Part must be unique for name, IPN and revision") raise ValidationError({ - "name": _("A part with this name already exists") + "name": msg, + "IPN": msg, }) except Part.DoesNotExist: pass @@ -280,8 +298,8 @@ class Part(models.Model): 'variant_of': _("Part cannot be a variant of another part if it is already a template"), }) - name = models.CharField(max_length=100, blank=False, unique=True, - help_text='Part name (must be unique)', + name = models.CharField(max_length=100, blank=False, + help_text='Part name', validators=[validators.validate_part_name] ) From a5306ec81b519b9a91741f8316e76f2d9f851569 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 20 Jun 2019 21:46:16 +1000 Subject: [PATCH 4/4] Add 'revision' field to part - e.g. different versions of a product - Can keep old versions in database and mark as inactive --- InvenTree/part/api.py | 1 + InvenTree/part/forms.py | 1 + .../part/migrations/0011_part_revision.py | 18 ++++++++++++++++++ InvenTree/part/models.py | 17 ++++++++++++++++- InvenTree/part/templates/part/detail.html | 8 +++++++- InvenTree/static/script/inventree/part.js | 5 +++++ 6 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 InvenTree/part/migrations/0011_part_revision.py diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 22f371c379..fbb73c1a12 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -119,6 +119,7 @@ class PartList(generics.ListCreateAPIView): 'image', 'name', 'IPN', + 'revision', 'description', 'keywords', 'is_template', diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index e268c2a167..1564c16316 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -93,6 +93,7 @@ class EditPartForm(HelperForm): 'name', 'IPN', 'description', + 'revision', 'keywords', 'variant_of', 'is_template', diff --git a/InvenTree/part/migrations/0011_part_revision.py b/InvenTree/part/migrations/0011_part_revision.py new file mode 100644 index 0000000000..2ae0aa6b19 --- /dev/null +++ b/InvenTree/part/migrations/0011_part_revision.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.2 on 2019-06-20 11:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0010_auto_20190620_2135'), + ] + + operations = [ + migrations.AddField( + model_name='part', + name='revision', + field=models.CharField(blank=True, help_text='Part revision or version number', max_length=100), + ), + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index f77e2d94f4..6a6ba6440c 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -246,6 +246,9 @@ class Part(models.Model): elements.append(self.name) + if self.revision: + elements.append(self.revision) + return ' | '.join(elements) def get_absolute_url(self): @@ -278,13 +281,15 @@ class Part(models.Model): try: parts = Part.objects.exclude(id=self.id).filter( name__iexact=self.name, - IPN__iexact=self.IPN) + IPN__iexact=self.IPN, + revision__iexact=self.revision) if parts.exists(): msg = _("Part must be unique for name, IPN and revision") raise ValidationError({ "name": msg, "IPN": msg, + "revision": msg, }) except Part.DoesNotExist: pass @@ -325,6 +330,8 @@ class Part(models.Model): IPN = models.CharField(max_length=100, blank=True, help_text='Internal Part Number') + revision = models.CharField(max_length=100, blank=True, help_text='Part revision or version number') + URL = models.URLField(blank=True, help_text='Link to extenal URL') image = models.ImageField(upload_to=rename_part_image, max_length=255, null=True, blank=True) @@ -803,6 +810,14 @@ class Part(models.Model): item.pk = None item.save() + # Copy the fields that aren't available in the duplicate form + self.salable = other.salable + self.assembly = other.assembly + self.component = other.component + self.purchaseable = other.purchaseable + self.trackable = other.trackable + self.virtual = other.virtual + self.save() def export_bom(self, **kwargs): diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 68ae0ed3bd..ddd917edc0 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -13,7 +13,7 @@ - + {% if part.IPN %} @@ -21,6 +21,12 @@ {% endif %} + {% if part.revision %} + + + + + {% endif %} diff --git a/InvenTree/static/script/inventree/part.js b/InvenTree/static/script/inventree/part.js index 83d21aa074..e8ae2662ed 100644 --- a/InvenTree/static/script/inventree/part.js +++ b/InvenTree/static/script/inventree/part.js @@ -126,6 +126,11 @@ function loadPartTable(table, url, options={}) { name += value; + if (row.revision) { + name += ' | '; + name += row.revision; + } + if (row.is_template) { name = '' + name + ''; }
Part name{{ part.full_name }}{{ part.name }}
{{ part.IPN }}
Revision{{ part.revision }}
Description {{ part.description }}