diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 91f0a66730..e82f33ee65 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -11,7 +11,8 @@ https://docs.djangoproject.com/en/1.10/ref/settings/ """ import os - +import logging +import logging.config # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -28,6 +29,12 @@ DEBUG = True ALLOWED_HOSTS = [] +if DEBUG: + # will output to your console + logging.basicConfig( + level = logging.DEBUG, + format = '%(asctime)s %(levelname)s %(message)s', + ) # Application definition diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index dd05862271..236649214f 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -3,6 +3,9 @@ from __future__ import unicode_literals import os +from django.utils.translation import gettext_lazy as _ +from django.core.exceptions import ValidationError + from django.db import models from django.db.models import Sum from django.core.validators import MinValueValidator @@ -348,6 +351,16 @@ class BomItem(models.Model): # Quantity required quantity = models.PositiveIntegerField(default=1, validators=[MinValueValidator(0)]) + def clean(self): + + # A part cannot refer to itself in its BOM + if self.part == self.sub_part: + raise ValidationError(_('A part cannot contain itself as a BOM item')) + + for item in self.sub_part.bom_items.all(): + if self.part == item.sub_part: + raise ValidationError(_("Part '{p1}' is used in BOM for '{p2}' (recursive)".format(p1=str(self.part), p2=str(self.sub_part)))) + class Meta: verbose_name = "BOM Item" diff --git a/InvenTree/part/templates/part/bom.html b/InvenTree/part/templates/part/bom.html index ec4c1635d9..1157279312 100644 --- a/InvenTree/part/templates/part/bom.html +++ b/InvenTree/part/templates/part/bom.html @@ -60,7 +60,10 @@ $(document).ready(function(){ var button = $(this); launchDeleteForm("#modal-delete", - button.attr('url')); + button.attr('url'), + { + reload: true + }); }); $('#bom-table').on('click', '.edit-row-button', function () { diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index f77550b609..1c765180c1 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext_lazy as _ +from django.core.exceptions import ValidationError from django.db import models, transaction from django.core.validators import MinValueValidator @@ -13,6 +14,8 @@ from datetime import datetime from InvenTree.models import InvenTreeTree +from part.models import Part + class StockLocation(InvenTreeTree): """ Organization tree for StockItem objects @@ -54,6 +57,26 @@ class StockItem(models.Model): If a serial number is assigned, then StockItem cannot have a quantity other than 1 """ + def clean(self): + + + # The 'supplier_part' field must point to the same part! + try: + if self.supplier_part is not None: + if not self.supplier_part.part == self.part: + raise ValidationError({ + 'supplier_part': _( + "Part type ('{pf}') must be {pe}").format( + pf=str(self.supplier_part.part), + pe=str(self.part) + ) + }) + except Part.DoesNotExist: + # This gets thrown if self.supplier_part is null + # TODO - Find a test than can be perfomed... + pass + + def get_absolute_url(self): return '/stock/item/{id}/'.format(id=self.id)