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.db import models
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from rest_framework.exceptions import ValidationError
|
|
||||||
|
|
||||||
from django.db.models.signals import pre_delete
|
from django.db.models.signals import pre_delete
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
@ -134,32 +133,6 @@ class InvenTreeTree(MPTTModel):
|
|||||||
"""
|
"""
|
||||||
return '/'.join([item.name for item in self.path])
|
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):
|
def __str__(self):
|
||||||
""" String representation of a category is the full path to that category """
|
""" 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 .validators import validate_overage, validate_part_name
|
||||||
from . import helpers
|
from . import helpers
|
||||||
|
|
||||||
|
from mptt.exceptions import InvalidMove
|
||||||
|
|
||||||
|
from stock.models import StockLocation
|
||||||
|
|
||||||
|
|
||||||
class ValidatorTest(TestCase):
|
class ValidatorTest(TestCase):
|
||||||
|
|
||||||
@ -103,6 +107,54 @@ class TestDownloadFile(TestCase):
|
|||||||
helpers.DownloadFile(bytes("hello world".encode("utf8")), "out.bin")
|
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):
|
class TestSerialNumberExtraction(TestCase):
|
||||||
""" Tests for serial number extraction code """
|
""" Tests for serial number extraction code """
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ Provides information on the current InvenTree version
|
|||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
INVENTREE_SW_VERSION = "0.0.4"
|
INVENTREE_SW_VERSION = "0.0.5"
|
||||||
|
|
||||||
|
|
||||||
def inventreeVersion():
|
def inventreeVersion():
|
||||||
|
@ -188,12 +188,12 @@ class StockItem(models.Model):
|
|||||||
if self.part.variant_of is not None:
|
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():
|
if StockItem.objects.filter(part__variant_of=self.part.variant_of, serial=self.serial).exclude(id=self.id).exists():
|
||||||
raise ValidationError({
|
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:
|
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({
|
raise ValidationError({
|
||||||
'serial': _('A part with this serial number already exists')
|
'serial': _('A stock item with this serial number already exists')
|
||||||
})
|
})
|
||||||
except Part.DoesNotExist:
|
except Part.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
@ -223,6 +223,9 @@ class StockExport(AjaxView):
|
|||||||
stock_items = stock_items.filter(customer=None)
|
stock_items = stock_items.filter(customer=None)
|
||||||
stock_items = stock_items.filter(belongs_to=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
|
# Column headers
|
||||||
headers = [
|
headers = [
|
||||||
_('Stock ID'),
|
_('Stock ID'),
|
||||||
|
2
Makefile
2
Makefile
@ -7,7 +7,7 @@ clean:
|
|||||||
rm -rf .tox
|
rm -rf .tox
|
||||||
rm -f .coverage
|
rm -f .coverage
|
||||||
|
|
||||||
update: backup migrate
|
update: backup install migrate
|
||||||
|
|
||||||
# Perform database migrations (after schema changes are made)
|
# Perform database migrations (after schema changes are made)
|
||||||
migrate:
|
migrate:
|
||||||
|
@ -83,6 +83,7 @@ Development and Testing
|
|||||||
Other shorthand functions are provided for the development and testing process:
|
Other shorthand functions are provided for the development and testing process:
|
||||||
|
|
||||||
* ``make install`` - Install all required underlying packages using PIP
|
* ``make install`` - Install all required underlying packages using PIP
|
||||||
|
* ``make update`` - Update InvenTree installation (after database configuration)
|
||||||
* ``make superuser`` - Create a superuser account
|
* ``make superuser`` - Create a superuser account
|
||||||
* ``make migrate`` - Perform database migrations
|
* ``make migrate`` - Perform database migrations
|
||||||
* ``make mysql`` - Install packages required for MySQL database backend
|
* ``make mysql`` - Install packages required for MySQL database backend
|
||||||
|
Loading…
Reference in New Issue
Block a user