diff --git a/docs/docs/sales/sales_order.md b/docs/docs/sales/sales_order.md index ebdf3d2e69..d1c8a790ff 100644 --- a/docs/docs/sales/sales_order.md +++ b/docs/docs/sales/sales_order.md @@ -234,3 +234,4 @@ The following [global settings](../settings/global.md) are available for sales o {{ globalsetting("SALESORDER_EDIT_COMPLETED_ORDERS") }} {{ globalsetting("SALESORDER_SHIP_COMPLETE") }} {{ globalsetting("SALESORDER_SHIPMENT_REQUIRES_CHECK") }} +{{ globalsetting("SALESORDER_BLOCK_INCOMPLETE_ITEM_TESTS")}} diff --git a/src/backend/InvenTree/common/setting/system.py b/src/backend/InvenTree/common/setting/system.py index b06db79589..395794b3de 100644 --- a/src/backend/InvenTree/common/setting/system.py +++ b/src/backend/InvenTree/common/setting/system.py @@ -910,6 +910,14 @@ SYSTEM_SETTINGS: dict[str, InvenTreeSettingsKeyType] = { 'default': False, 'validator': bool, }, + 'SALESORDER_BLOCK_INCOMPLETE_ITEM_TESTS': { + 'name': _('Block Incomplete Item Tests'), + 'description': _( + 'Prevent allocation of stock items to sales orders if required item tests are incomplete' + ), + 'default': False, + 'validator': bool, + }, 'PURCHASEORDER_REFERENCE_PATTERN': { 'name': _('Purchase Order Reference Pattern'), 'description': _( diff --git a/src/backend/InvenTree/order/serializers.py b/src/backend/InvenTree/order/serializers.py index c544d3b76d..80a2765b03 100644 --- a/src/backend/InvenTree/order/serializers.py +++ b/src/backend/InvenTree/order/serializers.py @@ -19,6 +19,7 @@ import order.models import part.filters as part_filters import stock.models import stock.serializers +from common.settings import get_global_setting from company.serializers import ( AddressBriefSerializer, CompanyBriefSerializer, @@ -1663,6 +1664,15 @@ class SalesOrderShipmentAllocationItemSerializer(serializers.Serializer): stock_item = data['stock_item'] quantity = data['quantity'] + if get_global_setting('SALESORDER_BLOCK_INCOMPLETE_ITEM_TESTS'): + if ( + stock_item.hasRequiredTests() + and not stock_item.passedAllRequiredTests() + ): + raise ValidationError({ + 'stock_item': _('Stock item has not passed all required tests') + }) + if stock_item.serialized and quantity != 1: raise ValidationError({ 'quantity': _('Quantity must be 1 for serialized stock item') @@ -1853,6 +1863,14 @@ class SalesOrderSerialAllocationSerializer(serializers.Serializer): stock_item = items[0] + if get_global_setting('SALESORDER_BLOCK_INCOMPLETE_ITEM_TESTS'): + if ( + stock_item.hasRequiredTests() + and not stock_item.passedAllRequiredTests() + ): + serials_unavailable.add(str(serial)) + continue + if not stock_item.in_stock: serials_unavailable.add(str(serial)) continue diff --git a/src/backend/InvenTree/order/test_api.py b/src/backend/InvenTree/order/test_api.py index 7996301b1d..fae21e6e37 100644 --- a/src/backend/InvenTree/order/test_api.py +++ b/src/backend/InvenTree/order/test_api.py @@ -2404,6 +2404,43 @@ class SalesOrderAllocateTest(OrderTest): assert_subset=True, ) + def test_block_on_required_tests(self): + """Test the SALESORDER_BLOCK_INCOMPLETE_ITEM_TESTS setting.""" + from part.models import PartTestTemplate + + line = self.order.lines.first() + part = line.part + + # Make this a testable part + part.testable = True + part.save() + + # Create a required test + PartTestTemplate.objects.create( + part=part, test_name='A required test', required=True + ) + + data = { + 'items': [ + { + 'line_item': line.pk, + 'stock_item': part.stock_items.last().pk, + 'quantity': line.quantity, + } + ] + } + + set_global_setting('SALESORDER_BLOCK_INCOMPLETE_ITEM_TESTS', True) + + response = self.post(self.url, data, expected_code=400) + self.assertIn( + 'Stock item has not passed all required tests', str(response.data) + ) + + set_global_setting('SALESORDER_BLOCK_INCOMPLETE_ITEM_TESTS', False) + + response = self.post(self.url, data, expected_code=201) + class ReturnOrderTests(InvenTreeAPITestCase): """Unit tests for ReturnOrder API endpoints.""" diff --git a/src/frontend/src/pages/Index/Settings/SystemSettings.tsx b/src/frontend/src/pages/Index/Settings/SystemSettings.tsx index 0556bac501..a8532c9c89 100644 --- a/src/frontend/src/pages/Index/Settings/SystemSettings.tsx +++ b/src/frontend/src/pages/Index/Settings/SystemSettings.tsx @@ -336,7 +336,8 @@ export default function SystemSettings() { 'SALESORDER_DEFAULT_SHIPMENT', 'SALESORDER_EDIT_COMPLETED_ORDERS', 'SALESORDER_SHIP_COMPLETE', - 'SALESORDER_SHIPMENT_REQUIRES_CHECK' + 'SALESORDER_SHIPMENT_REQUIRES_CHECK', + 'SALESORDER_BLOCK_INCOMPLETE_ITEM_TESTS' ]} />