From 108382cc8915fb2ffafaa22366bab4c9a74f4c33 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 9 Sep 2019 08:17:26 +1000 Subject: [PATCH 1/6] Prefecth related data for stock export - Example export reduced from 1,024 queries to 7 --- InvenTree/stock/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 29b5c5d6bb..26a957a644 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -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'), From 9c988310b6eaa0bb084557f81e19b5168879a174 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 9 Sep 2019 08:29:36 +1000 Subject: [PATCH 2/6] Add tests for MPTT models --- InvenTree/InvenTree/models.py | 26 ------------------ InvenTree/InvenTree/tests.py | 52 +++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/InvenTree/InvenTree/models.py b/InvenTree/InvenTree/models.py index 38539d0118..3b0560030b 100644 --- a/InvenTree/InvenTree/models.py +++ b/InvenTree/InvenTree/models.py @@ -134,32 +134,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 """ diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 4e238a6c80..2511cf4318 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -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 """ From fb2c347fd4012a6865ed81e357d645265414109d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 9 Sep 2019 08:30:24 +1000 Subject: [PATCH 3/6] Removed unused import --- InvenTree/InvenTree/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/InvenTree/InvenTree/models.py b/InvenTree/InvenTree/models.py index 3b0560030b..d5259b2acc 100644 --- a/InvenTree/InvenTree/models.py +++ b/InvenTree/InvenTree/models.py @@ -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 From 53c5324df6e93b728af5f2d8d3c8479487890b20 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 9 Sep 2019 08:49:27 +1000 Subject: [PATCH 4/6] Fix uniqueness test for stock item --- InvenTree/stock/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index e9220cabcb..c659801a0d 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -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 From da5f2338ebaafcda9c80997dbcff56d8ad92a485 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 9 Sep 2019 14:14:38 +1000 Subject: [PATCH 5/6] Ensure that required packages are installed when performing update step --- Makefile | 2 +- docs/start.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f6b054dab0..5d0f88babe 100644 --- a/Makefile +++ b/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: diff --git a/docs/start.rst b/docs/start.rst index 4abf01436c..f239bde858 100644 --- a/docs/start.rst +++ b/docs/start.rst @@ -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 From e4dcbd2fda0a93ad625db1f266ba5d44190df15c Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 9 Sep 2019 14:25:00 +1000 Subject: [PATCH 6/6] Update version.py Bump version num --- InvenTree/InvenTree/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 4a9a23e7ef..1766168a30 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -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():