diff --git a/src/backend/InvenTree/part/api.py b/src/backend/InvenTree/part/api.py index 6d31392606..81826daaa9 100644 --- a/src/backend/InvenTree/part/api.py +++ b/src/backend/InvenTree/part/api.py @@ -15,6 +15,7 @@ from rest_framework import serializers from rest_framework.response import Response import part.filters +import part.tasks as part_tasks from data_exporter.mixins import DataExportViewMixin from InvenTree.api import ( BulkCreateMixin, @@ -47,6 +48,7 @@ from InvenTree.mixins import ( SerializerContextMixin, UpdateAPI, ) +from InvenTree.tasks import offload_task from stock.models import StockLocation from . import serializers as part_serializers @@ -633,7 +635,14 @@ class PartValidateBOM(RetrieveUpdateAPI): valid = str2bool(serializer.validated_data.get('valid', False)) - part.validate_bom(request.user, valid=valid) + # BOM validation may take some time, so we offload it to a background task + offload_task( + part_tasks.validate_bom, + part.pk, + valid, + user_id=request.user.pk if request and request.user else None, + group='part', + ) # Re-serialize the response serializer = self.get_serializer(part, many=False) diff --git a/src/backend/InvenTree/part/tasks.py b/src/backend/InvenTree/part/tasks.py index 2704d43a22..ac21bad549 100644 --- a/src/backend/InvenTree/part/tasks.py +++ b/src/backend/InvenTree/part/tasks.py @@ -1,6 +1,7 @@ """Background task definitions for the 'part' app.""" from datetime import datetime, timedelta +from typing import Optional from django.core.exceptions import ValidationError from django.db.models import Model @@ -437,3 +438,35 @@ def check_bom_valid(part_id: int): if valid != part.bom_validated: part.bom_validated = valid part.save() + + +@tracer.start_as_current_span('validate_bom') +def validate_bom(part_id: int, valid: bool, user_id: Optional[int] = None): + """Run BOM validation for the specified Part. + + Arguments: + part_id: The ID of the part for which to validate the BOM. + valid: Boolean indicating whether the BOM is valid or not. + user_id: Optional ID of the user performing the validation. + """ + from django.contrib.auth import get_user_model + + from part.models import Part + + User = get_user_model() + + try: + part = Part.objects.get(pk=part_id) + except Part.DoesNotExist: + logger.warning('validate_bom: Part with ID %s does not exist', part_id) + return + + if user_id: + try: + user = User.objects.get(pk=user_id) + except User.DoesNotExist: + user = None + else: + user = None + + part.validate_bom(user, valid=valid) diff --git a/src/frontend/src/pages/part/PartDetail.tsx b/src/frontend/src/pages/part/PartDetail.tsx index aaa42fecef..a539b51078 100644 --- a/src/frontend/src/pages/part/PartDetail.tsx +++ b/src/frontend/src/pages/part/PartDetail.tsx @@ -184,7 +184,7 @@ function BomValidationInformation({ {t`Do you want to validate the bill of materials for this assembly?`} ), - successMessage: t`BOM validated`, + successMessage: t`Bill of materials scheduled for validation`, onFormSuccess: () => { bomInformationQuery.refetch(); }