Add 'variant' field to Part model

- Display 'long_name' which is concatenation of name and variant
This commit is contained in:
Oliver Walters 2019-05-10 22:17:13 +10:00
parent 164f98540d
commit f76f1f54ae
11 changed files with 70 additions and 18 deletions

View File

@ -65,6 +65,7 @@ class EditPartForm(HelperForm):
fields = [ fields = [
'category', 'category',
'name', 'name',
'variant',
'description', 'description',
'IPN', 'IPN',
'URL', 'URL',

View File

@ -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')},
),
]

View File

@ -124,6 +124,7 @@ class Part(models.Model):
Attributes: Attributes:
name: Brief name for this part 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 description: Longer form description of the part
category: The PartCategory to which this part belongs category: The PartCategory to which this part belongs
IPN: Internal part number (optional) IPN: Internal part number (optional)
@ -142,6 +143,23 @@ class Part(models.Model):
notes: Additional notes field for this part 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): def get_absolute_url(self):
""" Return the web URL for viewing this part """ """ Return the web URL for viewing this part """
return reverse('part-detail', kwargs={'pk': self.id}) return reverse('part-detail', kwargs={'pk': self.id})
@ -154,7 +172,9 @@ class Part(models.Model):
else: else:
return static('/img/blank_image.png') 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') 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) notes = models.TextField(blank=True)
def __str__(self):
return "{n} - {d}".format(n=self.name, d=self.description)
def format_barcode(self): def format_barcode(self):
""" Return a JSON string for formatting a barcode for this Part object """ """ 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 @property
def category_path(self): def category_path(self):
if self.category: if self.category:

View File

@ -41,9 +41,10 @@ class PartBriefSerializer(serializers.ModelSerializer):
'pk', 'pk',
'url', 'url',
'name', 'name',
'image_url', 'variant',
'description', 'description',
'available_stock', 'available_stock',
'image_url',
] ]
@ -63,6 +64,7 @@ class PartSerializer(serializers.ModelSerializer):
'pk', 'pk',
'url', # Link to the part detail page 'url', # Link to the part detail page
'name', 'name',
'variant',
'image_url', 'image_url',
'IPN', 'IPN',
'URL', # Link to an external URL (optional) 'URL', # Link to an external URL (optional)

View File

@ -4,7 +4,7 @@
{% block page_title %} {% block page_title %}
{% if part %} {% if part %}
InvenTree | Part - {{ part.name }} InvenTree | Part - {{ part.long_name }}
{% elif category %} {% elif category %}
InvenTree | Part Category - {{ category }} InvenTree | Part Category - {{ category }}
{% else %} {% else %}

View File

@ -7,7 +7,7 @@
<div class="row"> <div class="row">
{% if part.active == False %} {% if part.active == False %}
<div class='alert alert-danger' style='display: block;'> <div class='alert alert-danger' style='display: block;'>
This part ({{ part.name }}) is not active: This part ({{ part.long_name }}) is not active:
</div> </div>
{% endif %} {% endif %}
<div class="col-sm-6"> <div class="col-sm-6">
@ -24,8 +24,11 @@
</div> </div>
<div class="media-body"> <div class="media-body">
<h4> <h4>
{{ part.name }} {{ part.long_name }}
</h4> </h4>
{% if part.variant %}
<p>Variant: {{ part.variant }}</p>
{% endif %}
<p><i>{{ part.description }}</i></p> <p><i>{{ part.description }}</i></p>
<p> <p>
<div class='btn-group'> <div class='btn-group'>

View File

@ -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 %} {% if part.used_in_count %}
<p>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: <p>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 %} {% endif %}
{% if part.serials.all|length > 0 %} {% if part.serials.all|length > 0 %}
<p>There are {{ part.serials.all|length }} unique parts tracked for '{{ part.name }}'. Deleting this part will permanently remove this tracking information.</p> <p>There are {{ part.serials.all|length }} unique parts tracked for '{{ part.long_name }}'. Deleting this part will permanently remove this tracking information.</p>
{% endif %} {% endif %}

View File

@ -48,7 +48,7 @@
$("#supplier-table").bootstrapTable({ $("#supplier-table").bootstrapTable({
sortable: true, sortable: true,
search: 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) { queryParams: function(p) {
return { return {
part: {{ part.id }} part: {{ part.id }}

View File

@ -4,7 +4,7 @@
{% include 'part/tabs.html' with tab='track' %} {% include 'part/tabs.html' with tab='track' %}
Part tracking for {{ part.name }} Part tracking for {{ part.long_name }}
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>

View File

@ -123,7 +123,13 @@ function loadPartTable(table, url, options={}) {
title: 'Part', title: 'Part',
sortable: true, sortable: true,
formatter: function(value, row, index, field) { 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) { if (!row.active) {
display = display + "<span class='label label-warning' style='float: right;'>INACTIVE</span>"; display = display + "<span class='label label-warning' style='float: right;'>INACTIVE</span>";
} }

View File

@ -8,7 +8,7 @@
</tr> </tr>
{% for part in parts %} {% for part in parts %}
<tr> <tr>
<td><a href="{% url 'part-detail' part.id %}">{{ part.name }}</a></td> <td><a href="{% url 'part-detail' part.id %}">{{ part.long_name }}</a></td>
<td>{{ part.description }}</td> <td>{{ part.description }}</td>
<td>{{ part.total_stock }}</td> <td>{{ part.total_stock }}</td>
<td>{{ part.allocation_count }}</td> <td>{{ part.allocation_count }}</td>