Add setting to allow or prohibit duplicate IPN values

This commit is contained in:
Oliver Walters 2020-11-10 09:03:26 +11:00
parent eead52a5dd
commit a6028f027a
6 changed files with 73 additions and 0 deletions

View File

@ -64,6 +64,13 @@ class InvenTreeSetting(models.Model):
'description': _('Regular expression pattern for matching Part IPN')
},
'PART_ALLOW_DUPLICATE_IPN': {
'name': _('Allow Duplicate IPN'),
'description': _('Allow multiple parts to share the same IPN'),
'default': True,
'validator': bool,
},
'PART_COPY_BOM': {
'name': _('Copy Part BOM Data'),
'description': _('Copy BOM data by default when duplicating a part'),
@ -306,6 +313,10 @@ class InvenTreeSetting(models.Model):
else:
return
# Enforce standard boolean representation
if setting.is_bool():
value = InvenTree.helpers.str2bool(value)
setting.value = str(value)
setting.save()
@ -317,6 +328,10 @@ class InvenTreeSetting(models.Model):
def name(self):
return InvenTreeSetting.get_setting_name(self.key)
@property
def default_value(self):
return InvenTreeSetting.get_default_value(self.key)
@property
def description(self):
return InvenTreeSetting.get_setting_description(self.key)

View File

@ -70,3 +70,13 @@ class SettingsTest(TestCase):
InvenTreeSetting.set_setting(key, value, self.user)
self.assertEqual(value, InvenTreeSetting.get_setting(key))
# Any fields marked as 'boolean' must have a default value specified
setting = InvenTreeSetting.get_setting_object(key)
if setting.is_bool():
if setting.default_value in ['', None]:
raise ValueError(f'Default value for boolean setting {key} not provided')
if setting.default_value not in [True, False]:
raise ValueError(f'Non-boolean default value specified for {key}')

View File

@ -529,6 +529,18 @@ class Part(MPTTModel):
"""
super().validate_unique(exclude)
# User can decide whether duplicate IPN (Internal Part Number) values are allowed
allow_duplicate_ipn = common.models.InvenTreeSetting.get_setting('PART_ALLOW_DUPLICATE_IPN')
if not allow_duplicate_ipn:
parts = Part.objects.filter(IPN__iexact=self.IPN)
parts = parts.exclude(pk=self.pk)
if parts.exists():
raise ValidationError({
'IPN': _('Duplicate IPN not allowed in part settings'),
})
# Part name uniqueness should be case insensitive
try:
parts = Part.objects.exclude(id=self.id).filter(

View File

@ -249,3 +249,28 @@ class PartSettingsTest(TestCase):
self.assertEqual(part.trackable, val)
Part.objects.filter(pk=part.pk).delete()
def test_duplicate_ipn(self):
"""
Test the setting which controls duplicate IPN values
"""
# Create a part
Part.objects.create(name='Hello', description='A thing', IPN='IPN123')
# Attempt to create a duplicate item (should fail)
with self.assertRaises(ValidationError):
Part.objects.create(name='Hello', description='A thing', IPN='IPN123')
# Attempt to create item with duplicate IPN (should be allowed by default)
Part.objects.create(name='Hello', description='A thing', IPN='IPN123', revision='B')
# And attempt again with the same values (should fail)
with self.assertRaises(ValidationError):
Part.objects.create(name='Hello', description='A thing', IPN='IPN123', revision='B')
# Now update the settings so duplicate IPN values are *not* allowed
InvenTreeSetting.set_setting('PART_ALLOW_DUPLICATE_IPN', False, self.user)
with self.assertRaises(ValidationError):
Part.objects.create(name='Hello', description='A thing', IPN='IPN123', revision='C')

View File

@ -1247,12 +1247,21 @@ class StockItem(MPTTModel):
@property
def required_test_count(self):
"""
Return the number of 'required tests' for this StockItem
"""
return self.part.getRequiredTests().count()
def hasRequiredTests(self):
"""
Return True if there are any 'required tests' associated with this StockItem
"""
return self.part.getRequiredTests().count() > 0
def passedAllRequiredTests(self):
"""
Returns True if this StockItem has passed all required tests
"""
status = self.requiredTestStatus()

View File

@ -17,6 +17,8 @@
<thead></thead>
<tbody>
{% include "InvenTree/settings/setting.html" with key="PART_IPN_REGEX" %}
{% include "InvenTree/settings/setting.html" with key="PART_ALLOW_DUPLICATE_IPN" %}
<tr><td colspan='4'></td></tr>
{% include "InvenTree/settings/setting.html" with key="PART_COMPONENT" %}
{% include "InvenTree/settings/setting.html" with key="PART_PURCHASEABLE" %}
{% include "InvenTree/settings/setting.html" with key="PART_SALABLE" %}