2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-29 20:16:44 +00:00

[Build] Add extra validation options (#7560)

* Add new setting: BUILDORDER_REQUIRE_VALID_BOM

- Prevent build orders from being created if the assembly BOM has not been validated

* Add validation check when creating a build order

* Add unit tests
This commit is contained in:
Oliver 2024-07-05 12:46:34 +10:00 committed by GitHub
parent 720651602b
commit 13dbfd0b14
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 94 additions and 0 deletions

View File

@ -120,8 +120,23 @@ class Build(
self.validate_reference_field(self.reference) self.validate_reference_field(self.reference)
self.reference_int = self.rebuild_reference_field(self.reference) self.reference_int = self.rebuild_reference_field(self.reference)
if get_global_setting('BUILDORDER_REQUIRE_VALID_BOM'):
# Check that the BOM is valid
if not self.part.is_bom_valid():
raise ValidationError({
'part': _('Assembly BOM has not been validated')
})
if get_global_setting('BUILDORDER_REQUIRE_ACTIVE_PART'):
# Check that the part is active
if not self.part.active:
raise ValidationError({
'part': _('Part is not active')
})
# On first save (i.e. creation), run some extra checks # On first save (i.e. creation), run some extra checks
if self.pk is None: if self.pk is None:
# Set the destination location (if not specified) # Set the destination location (if not specified)
if not self.destination: if not self.destination:
self.destination = self.part.get_default_location() self.destination = self.part.get_default_location()

View File

@ -1,6 +1,7 @@
"""Basic unit tests for the BuildOrder app""" """Basic unit tests for the BuildOrder app"""
from django.conf import settings from django.conf import settings
from django.core.exceptions import ValidationError
from django.test import tag from django.test import tag
from django.urls import reverse from django.urls import reverse
@ -9,8 +10,10 @@ from datetime import datetime, timedelta
from InvenTree.unit_test import InvenTreeTestCase from InvenTree.unit_test import InvenTreeTestCase
from .models import Build from .models import Build
from part.models import Part, BomItem
from stock.models import StockItem from stock.models import StockItem
from common.settings import get_global_setting, set_global_setting
from build.status_codes import BuildStatus from build.status_codes import BuildStatus
@ -88,6 +91,64 @@ class BuildTestSimple(InvenTreeTestCase):
self.assertEqual(build.status, BuildStatus.CANCELLED) self.assertEqual(build.status, BuildStatus.CANCELLED)
def test_build_create(self):
"""Test creation of build orders via API."""
n = Build.objects.count()
# Find an assembly part
assembly = Part.objects.filter(assembly=True).first()
self.assertEqual(assembly.get_bom_items().count(), 0)
# Let's create some BOM items for this assembly
for component in Part.objects.filter(assembly=False, component=True)[:15]:
try:
BomItem.objects.create(
part=assembly,
sub_part=component,
reference='xxx',
quantity=5
)
except ValidationError:
pass
# The assembly has a BOM, and is now *invalid*
self.assertGreater(assembly.get_bom_items().count(), 0)
self.assertFalse(assembly.is_bom_valid())
# Create a build for an assembly with an *invalid* BOM
set_global_setting('BUILDORDER_REQUIRE_VALID_BOM', False)
set_global_setting('BUILDORDER_REQUIRE_ACTIVE_PART', True)
bo = Build.objects.create(part=assembly, quantity=10, reference='BO-9990')
bo.save()
# Now, require a *valid* BOM
set_global_setting('BUILDORDER_REQUIRE_VALID_BOM', True)
with self.assertRaises(ValidationError):
bo = Build.objects.create(part=assembly, quantity=10, reference='BO-9991')
# Now, validate the BOM, and try again
assembly.validate_bom(None)
self.assertTrue(assembly.is_bom_valid())
bo = Build.objects.create(part=assembly, quantity=10, reference='BO-9992')
# Now, try and create a build for an inactive assembly
assembly.active = False
assembly.save()
with self.assertRaises(ValidationError):
bo = Build.objects.create(part=assembly, quantity=10, reference='BO-9993')
set_global_setting('BUILDORDER_REQUIRE_ACTIVE_PART', False)
Build.objects.create(part=assembly, quantity=10, reference='BO-9994')
# Check that expected quantity of new builds is created
self.assertEqual(Build.objects.count(), n + 3)
class TestBuildViews(InvenTreeTestCase): class TestBuildViews(InvenTreeTestCase):
"""Tests for Build app views.""" """Tests for Build app views."""

View File

@ -1786,6 +1786,20 @@ class InvenTreeSetting(BaseInvenTreeSetting):
'default': False, 'default': False,
'validator': bool, 'validator': bool,
}, },
'BUILDORDER_REQUIRE_ACTIVE_PART': {
'name': _('Require Active Part'),
'description': _('Prevent build order creation for inactive parts'),
'default': False,
'validator': bool,
},
'BUILDORDER_REQUIRE_VALID_BOM': {
'name': _('Require Valid BOM'),
'description': _(
'Prevent build order creation unless BOM has been validated'
),
'default': False,
'validator': bool,
},
'PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS': { 'PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS': {
'name': _('Block Until Tests Pass'), 'name': _('Block Until Tests Pass'),
'description': _( 'description': _(

View File

@ -14,6 +14,8 @@
<tbody> <tbody>
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REFERENCE_PATTERN" %} {% include "InvenTree/settings/setting.html" with key="BUILDORDER_REFERENCE_PATTERN" %}
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REQUIRE_RESPONSIBLE" %} {% include "InvenTree/settings/setting.html" with key="BUILDORDER_REQUIRE_RESPONSIBLE" %}
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REQUIRE_ACTIVE_PART" %}
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REQUIRE_VALID_BOM" %}
{% include "InvenTree/settings/setting.html" with key="PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS" %} {% include "InvenTree/settings/setting.html" with key="PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS" %}
</tbody> </tbody>
</table> </table>

View File

@ -245,6 +245,8 @@ export default function SystemSettings() {
keys={[ keys={[
'BUILDORDER_REFERENCE_PATTERN', 'BUILDORDER_REFERENCE_PATTERN',
'BUILDORDER_REQUIRE_RESPONSIBLE', 'BUILDORDER_REQUIRE_RESPONSIBLE',
'BUILDORDER_REQUIRE_ACTIVE_PART',
'BUILDORDER_REQUIRE_VALID_BOM',
'PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS' 'PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS'
]} ]}
/> />