diff --git a/src/backend/InvenTree/build/models.py b/src/backend/InvenTree/build/models.py index 9bd92609eb..0ebe93fbab 100644 --- a/src/backend/InvenTree/build/models.py +++ b/src/backend/InvenTree/build/models.py @@ -37,7 +37,7 @@ from build.validators import ( validate_build_order_reference, ) from common.models import ProjectCode -from common.notifications import InvenTreeNotificationBodies, trigger_notification +from common.notifications import trigger_notification from common.settings import ( get_global_setting, prevent_build_output_complete_on_incompleted_tests, @@ -839,27 +839,6 @@ class Build( remove_allocated_stock = kwargs.get('remove_allocated_stock', False) remove_incomplete_outputs = kwargs.get('remove_incomplete_outputs', False) - if remove_allocated_stock: - # Offload task to remove allocated stock - if not InvenTree.tasks.offload_task( - build.tasks.complete_build_allocations, - self.pk, - user.pk if user else None, - group='build', - ): - raise ValidationError( - _('Failed to offload task to complete build allocations') - ) - - else: - self.allocated_stock.all().delete() - - # Remove incomplete outputs (if required) - if remove_incomplete_outputs: - outputs = self.build_outputs.filter(is_building=True) - - outputs.delete() - # Date of 'completion' is the date the build was cancelled self.completion_date = InvenTree.helpers.current_date() self.completed_by = user @@ -867,17 +846,17 @@ class Build( self.status = BuildStatus.CANCELLED.value self.save() - # Notify users that the order has been canceled - InvenTree.helpers_model.notify_responsible( - self, - Build, - exclude=self.issued_by, - content=InvenTreeNotificationBodies.OrderCanceled, - extra_users=self.part.get_subscribers(), + # Offload background task to take care of the expensive operations + InvenTree.tasks.offload_task( + build.tasks.cancel_build( + self.pk, + user.pk if user else None, + remove_allocated_stock=remove_allocated_stock, + remove_incomplete_outputs=remove_incomplete_outputs, + group='build', + ) ) - trigger_event(BuildEvents.CANCELLED, id=self.pk) - @transaction.atomic def deallocate_stock(self, build_line=None, output=None): """Deallocate stock from this Build. diff --git a/src/backend/InvenTree/build/tasks.py b/src/backend/InvenTree/build/tasks.py index a2f690048a..5bdb167910 100644 --- a/src/backend/InvenTree/build/tasks.py +++ b/src/backend/InvenTree/build/tasks.py @@ -207,6 +207,46 @@ def complete_build_outputs( ) +@tracer.start_as_current_span('cancel_build') +def cancel_build( + build_id: int, + user_id: int, + remove_allocated_stock: bool = False, + remove_incomplete_outputs: bool = False, +): + """Tasks to run after a BuildOrder is cancelled. + + Arguments: + build_id: The ID of the BuildOrder which has been cancelled + user_id: The ID of the user who cancelled the BuildOrder + remove_allocated_stock: If True, deallocate any allocated stock + remove_incomplete_outputs: If True, delete any incomplete build outputs + + """ + from build.models import Build + + build = Build.objects.get(pk=build_id) + + if remove_allocated_stock: + complete_build_allocations(build_id, user_id) + else: + build.allocated_stock.all().delete() + + if remove_incomplete_outputs: + build.build_outputs.filter(is_building=True).delete() + + # Notify users that the order has been canceled + InvenTree.helpers_model.notify_responsible( + build, + Build, + exclude=build.issued_by, + content=common.notifications.InvenTreeNotificationBodies.OrderCanceled, + extra_users=build.part.get_subscribers(), + ) + + trigger_event(BuildEvents.CANCELLED, id=build.pk) + + @tracer.start_as_current_span('update_build_order_lines') def update_build_order_lines(bom_item_pk: int): """Update all BuildOrderLineItem objects which reference a particular BomItem.