Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2019-06-20 21:49:30 +10:00
commit 6da0106aa2
12 changed files with 106 additions and 12 deletions

View File

@ -26,12 +26,12 @@ InvenTree | Company - {{ company.name }}
<p>{{ company.description }}</p> <p>{{ company.description }}</p>
<div class='btn-group'> <div class='btn-group'>
{% if company.is_supplier %} {% if company.is_supplier %}
<button type='button' class='btn btn-default btn-glyph' id='company-order' title='Create purchase order'> <button type='button' class='btn btn-default btn-glyph' id='company-order-2' title='Create purchase order'>
<span class='glyphicon glyphicon-shopping-cart'/> <span class='glyphicon glyphicon-shopping-cart'/>
</button> </button>
{% endif %} {% endif %}
<button type='button' class='btn btn-default btn-glyph' id='company-edit' title='Edit company information'> <button type='button' class='btn btn-default btn-glyph' id='company-edit' title='Edit company information'>
<span class='glyphicon glyphicon-cog'/> <span class='glyphicon glyphicon-edit'/>
</button> </button>
<button type='button' class='btn btn-default btn-glyph' id='company-delete' title='Delete company'> <button type='button' class='btn btn-default btn-glyph' id='company-delete' title='Delete company'>
<span class='glyphicon glyphicon-trash'/> <span class='glyphicon glyphicon-trash'/>
@ -98,6 +98,17 @@ InvenTree | Company - {{ company.name }}
}); });
}); });
$("#company-order-2").click(function() {
launchModalForm("{% url 'purchase-order-create' %}",
{
data: {
supplier: {{ company.id }},
},
follow: true,
});
});
$('#company-delete').click(function() { $('#company-delete').click(function() {
launchModalForm( launchModalForm(
"{% url 'company-delete' company.id %}", "{% url 'company-delete' company.id %}",

View File

@ -119,6 +119,7 @@ class PartList(generics.ListCreateAPIView):
'image', 'image',
'name', 'name',
'IPN', 'IPN',
'revision',
'description', 'description',
'keywords', 'keywords',
'is_template', 'is_template',

View File

@ -93,6 +93,7 @@ class EditPartForm(HelperForm):
'name', 'name',
'IPN', 'IPN',
'description', 'description',
'revision',
'keywords', 'keywords',
'variant_of', 'variant_of',
'is_template', 'is_template',

View File

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

View File

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

View File

@ -203,6 +203,7 @@ class Part(models.Model):
description: Longer form description of the part description: Longer form description of the part
keywords: Optional keywords for improving part search results keywords: Optional keywords for improving part search results
IPN: Internal part number (optional) 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 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) URL: Link to an external page with more information about this part (e.g. internal Wiki)
image: Image of this part image: Image of this part
@ -245,6 +246,9 @@ class Part(models.Model):
elements.append(self.name) elements.append(self.name)
if self.revision:
elements.append(self.revision)
return ' | '.join(elements) return ' | '.join(elements)
def get_absolute_url(self): def get_absolute_url(self):
@ -260,13 +264,32 @@ class Part(models.Model):
return static('/img/blank_image.png') return static('/img/blank_image.png')
def validate_unique(self, exclude=None): 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) super().validate_unique(exclude)
# Part name uniqueness should be case insensitive # Part name uniqueness should be case insensitive
try: 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,
revision__iexact=self.revision)
if parts.exists():
msg = _("Part must be unique for name, IPN and revision")
raise ValidationError({ raise ValidationError({
"name": _("A part with this name already exists") "name": msg,
"IPN": msg,
"revision": msg,
}) })
except Part.DoesNotExist: except Part.DoesNotExist:
pass pass
@ -280,8 +303,8 @@ class Part(models.Model):
'variant_of': _("Part cannot be a variant of another part if it is already a template"), '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, name = models.CharField(max_length=100, blank=False,
help_text='Part name (must be unique)', help_text='Part name',
validators=[validators.validate_part_name] validators=[validators.validate_part_name]
) )
@ -307,6 +330,8 @@ class Part(models.Model):
IPN = models.CharField(max_length=100, blank=True, help_text='Internal Part Number') 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') 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) image = models.ImageField(upload_to=rename_part_image, max_length=255, null=True, blank=True)
@ -785,6 +810,14 @@ class Part(models.Model):
item.pk = None item.pk = None
item.save() 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() self.save()
def export_bom(self, **kwargs): def export_bom(self, **kwargs):

View File

@ -22,7 +22,7 @@
</button> </button>
{% if category %} {% if category %}
<button class='btn btn-default btn-glyph' id='cat-edit' title='Edit part category'> <button class='btn btn-default btn-glyph' id='cat-edit' title='Edit part category'>
<span class='glyphicon glyphicon-cog'/> <span class='glyphicon glyphicon-edit'/>
</button> </button>
<button class='btn btn-default btn-glyph' id='cat-delete' title='Delete part category'> <button class='btn btn-default btn-glyph' id='cat-delete' title='Delete part category'>
<span class='glyphicon glyphicon-trash'/> <span class='glyphicon glyphicon-trash'/>

View File

@ -13,7 +13,7 @@
<table class='table table-striped'> <table class='table table-striped'>
<tr> <tr>
<td><b>Part name</b></td> <td><b>Part name</b></td>
<td>{{ part.full_name }}</td> <td>{{ part.name }}</td>
</tr> </tr>
{% if part.IPN %} {% if part.IPN %}
<tr> <tr>
@ -21,6 +21,12 @@
<td>{{ part.IPN }}</td> <td>{{ part.IPN }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% if part.revision %}
<tr>
<td><b>Revision</b></td>
<td>{{ part.revision }}</td>
</tr>
{% endif %}
<tr> <tr>
<td><b>Description</b></td> <td><b>Description</b></td>
<td>{{ part.description }}</td> <td>{{ part.description }}</td>

View File

@ -189,8 +189,8 @@ function loadBomTable(table, options) {
if (options.editable) { if (options.editable) {
cols.push({ cols.push({
formatter: function(value, row, index, field) { formatter: function(value, row, index, field) {
var bEdit = "<button title='Edit BOM Item' class='btn btn-default btn-glyph' type='button' url='/part/bom/" + row.pk + "/edit'><span class='glyphicon glyphicon-edit'/></button>"; var bEdit = "<button title='Edit BOM Item' class='bom-edit-button btn btn-default btn-glyph' type='button' url='/part/bom/" + row.pk + "/edit'><span class='glyphicon glyphicon-edit'/></button>";
var bDelt = "<button title='Delete BOM Item' class='btn btn-default btn-glyph' type='button' url='/part/bom/" + row.pk + "/delete'><span class='glyphicon glyphicon-trash'/></button>"; var bDelt = "<button title='Delete BOM Item' class='bom-delete-button btn btn-default btn-glyph' type='button' url='/part/bom/" + row.pk + "/delete'><span class='glyphicon glyphicon-trash'/></button>";
return "<div class='btn-group'>" + bEdit + bDelt + "</div>"; return "<div class='btn-group'>" + bEdit + bDelt + "</div>";
} }

View File

@ -126,6 +126,11 @@ function loadPartTable(table, url, options={}) {
name += value; name += value;
if (row.revision) {
name += ' | ';
name += row.revision;
}
if (row.is_template) { if (row.is_template) {
name = '<i>' + name + '</i>'; name = '<i>' + name + '</i>';
} }

View File

@ -27,7 +27,7 @@
</button> </button>
{% endif %} {% endif %}
<button type='button' class='btn btn-default btn-glyph' id='stock-edit' title='Edit stock item'> <button type='button' class='btn btn-default btn-glyph' id='stock-edit' title='Edit stock item'>
<span class='glyphicon glyphicon-cog'/> <span class='glyphicon glyphicon-edit'/>
</button> </button>
<button type='button' class='btn btn-default btn-glyph' id='stock-delete' title='Edit stock item'> <button type='button' class='btn btn-default btn-glyph' id='stock-delete' title='Edit stock item'>
<span class='glyphicon glyphicon-trash'/> <span class='glyphicon glyphicon-trash'/>

View File

@ -22,7 +22,7 @@
<span class='glyphicon glyphicon-ok-circle'/> <span class='glyphicon glyphicon-ok-circle'/>
</button> </button>
<button class='btn btn-default btn-glyph' id='location-edit' title='Edit stock location'> <button class='btn btn-default btn-glyph' id='location-edit' title='Edit stock location'>
<span class='glyphicon glyphicon-cog'/> <span class='glyphicon glyphicon-edit'/>
</button> </button>
<button class='btn btn-default btn-glyph' id='location-delete' title='Delete stock location'> <button class='btn btn-default btn-glyph' id='location-delete' title='Delete stock location'>
<span class='glyphicon glyphicon-trash'/> <span class='glyphicon glyphicon-trash'/>