mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
commit
a6e850e39f
@ -6,7 +6,6 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from django.db.models.signals import pre_delete
|
||||
from django.dispatch import receiver
|
||||
@ -134,32 +133,6 @@ class InvenTreeTree(MPTTModel):
|
||||
"""
|
||||
return '/'.join([item.name for item in self.path])
|
||||
|
||||
def clean(self):
|
||||
""" Custom cleaning
|
||||
|
||||
Parent:
|
||||
Setting the parent of an item to its own child results in an infinite loop.
|
||||
The parent of an item cannot be set to:
|
||||
a) Its own ID
|
||||
b) The ID of any child items that exist underneath it
|
||||
|
||||
Name:
|
||||
Tree node names are limited to a reduced character set
|
||||
"""
|
||||
|
||||
super().clean()
|
||||
|
||||
# Parent cannot be set to same ID (this would cause looping)
|
||||
try:
|
||||
if self.parent.id == self.id:
|
||||
raise ValidationError("Category cannot set itself as parent")
|
||||
except:
|
||||
pass
|
||||
|
||||
# Ensure that the new parent is not already a child
|
||||
if self.pk is not None and self.id in self.getUniqueChildren(include_self=False):
|
||||
raise ValidationError("Category cannot set a child as parent")
|
||||
|
||||
def __str__(self):
|
||||
""" String representation of a category is the full path to that category """
|
||||
|
||||
|
@ -5,6 +5,10 @@ from django.core.exceptions import ValidationError
|
||||
from .validators import validate_overage, validate_part_name
|
||||
from . import helpers
|
||||
|
||||
from mptt.exceptions import InvalidMove
|
||||
|
||||
from stock.models import StockLocation
|
||||
|
||||
|
||||
class ValidatorTest(TestCase):
|
||||
|
||||
@ -103,6 +107,54 @@ class TestDownloadFile(TestCase):
|
||||
helpers.DownloadFile(bytes("hello world".encode("utf8")), "out.bin")
|
||||
|
||||
|
||||
class TestMPTT(TestCase):
|
||||
""" Tests for the MPTT tree models """
|
||||
|
||||
fixtures = [
|
||||
'location',
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
StockLocation.objects.rebuild()
|
||||
|
||||
def test_self_as_parent(self):
|
||||
""" Test that we cannot set self as parent """
|
||||
|
||||
loc = StockLocation.objects.get(pk=4)
|
||||
loc.parent = loc
|
||||
|
||||
with self.assertRaises(InvalidMove):
|
||||
loc.save()
|
||||
|
||||
def test_child_as_parent(self):
|
||||
""" Test that we cannot set a child as parent """
|
||||
|
||||
parent = StockLocation.objects.get(pk=4)
|
||||
child = StockLocation.objects.get(pk=5)
|
||||
|
||||
parent.parent = child
|
||||
|
||||
with self.assertRaises(InvalidMove):
|
||||
parent.save()
|
||||
|
||||
def test_move(self):
|
||||
""" Move an item to a different tree """
|
||||
|
||||
drawer = StockLocation.objects.get(name='Drawer_1')
|
||||
|
||||
# Record the tree ID
|
||||
tree = drawer.tree_id
|
||||
|
||||
home = StockLocation.objects.get(name='Home')
|
||||
|
||||
drawer.parent = home
|
||||
drawer.save()
|
||||
|
||||
self.assertNotEqual(tree, drawer.tree_id)
|
||||
|
||||
|
||||
class TestSerialNumberExtraction(TestCase):
|
||||
""" Tests for serial number extraction code """
|
||||
|
||||
|
@ -4,7 +4,7 @@ Provides information on the current InvenTree version
|
||||
|
||||
import subprocess
|
||||
|
||||
INVENTREE_SW_VERSION = "0.0.4"
|
||||
INVENTREE_SW_VERSION = "0.0.5"
|
||||
|
||||
|
||||
def inventreeVersion():
|
||||
|
@ -188,12 +188,12 @@ class StockItem(models.Model):
|
||||
if self.part.variant_of is not None:
|
||||
if StockItem.objects.filter(part__variant_of=self.part.variant_of, serial=self.serial).exclude(id=self.id).exists():
|
||||
raise ValidationError({
|
||||
'serial': _('A part with this serial number already exists for template part {part}'.format(part=self.part.variant_of))
|
||||
'serial': _('A stock item with this serial number already exists for template part {part}'.format(part=self.part.variant_of))
|
||||
})
|
||||
else:
|
||||
if StockItem.objects.filter(serial=self.serial).exclude(id=self.id).exists():
|
||||
if StockItem.objects.filter(part=self.part, serial=self.serial).exclude(id=self.id).exists():
|
||||
raise ValidationError({
|
||||
'serial': _('A part with this serial number already exists')
|
||||
'serial': _('A stock item with this serial number already exists')
|
||||
})
|
||||
except Part.DoesNotExist:
|
||||
pass
|
||||
|
@ -223,6 +223,9 @@ class StockExport(AjaxView):
|
||||
stock_items = stock_items.filter(customer=None)
|
||||
stock_items = stock_items.filter(belongs_to=None)
|
||||
|
||||
# Pre-fetch related fields to reduce DB queries
|
||||
stock_items = stock_items.prefetch_related('part', 'supplier_part__supplier', 'location', 'purchase_order', 'build')
|
||||
|
||||
# Column headers
|
||||
headers = [
|
||||
_('Stock ID'),
|
||||
|
2
Makefile
2
Makefile
@ -7,7 +7,7 @@ clean:
|
||||
rm -rf .tox
|
||||
rm -f .coverage
|
||||
|
||||
update: backup migrate
|
||||
update: backup install migrate
|
||||
|
||||
# Perform database migrations (after schema changes are made)
|
||||
migrate:
|
||||
|
@ -83,6 +83,7 @@ Development and Testing
|
||||
Other shorthand functions are provided for the development and testing process:
|
||||
|
||||
* ``make install`` - Install all required underlying packages using PIP
|
||||
* ``make update`` - Update InvenTree installation (after database configuration)
|
||||
* ``make superuser`` - Create a superuser account
|
||||
* ``make migrate`` - Perform database migrations
|
||||
* ``make mysql`` - Install packages required for MySQL database backend
|
||||
|
Loading…
Reference in New Issue
Block a user