2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-11-30 01:10:00 +00:00

Offload stock consume operations (#10856)

- These can be expensive if there are a lot of allocated items
- Offload to the background worker
This commit is contained in:
Oliver
2025-11-19 15:40:24 +11:00
committed by GitHub
parent d06d80fb99
commit 40fbb4d810
3 changed files with 64 additions and 17 deletions

View File

@@ -39,6 +39,7 @@ from InvenTree.serializers import (
NotesFieldMixin,
enable_filter,
)
from InvenTree.tasks import offload_task
from stock.generators import generate_batch_code
from stock.models import StockItem, StockLocation
from stock.serializers import (
@@ -51,6 +52,7 @@ from users.serializers import OwnerSerializer, UserSerializer
from .models import Build, BuildItem, BuildLine
from .status_codes import BuildStatus
from .tasks import consume_build_item, consume_build_line
class BuildSerializer(
@@ -1845,12 +1847,14 @@ class BuildConsumeSerializer(serializers.Serializer):
return data
@transaction.atomic
def save(self):
"""Perform the stock consumption step."""
data = self.validated_data
request = self.context.get('request')
notes = data.get('notes', '')
# We may be passed either a list of BuildItem or BuildLine instances
items = data.get('items', [])
lines = data.get('lines', [])
@@ -1865,25 +1869,23 @@ class BuildConsumeSerializer(serializers.Serializer):
# Instead, it gets consumed when the output is completed
continue
build_item.complete_allocation(
quantity=quantity,
# Offload a background task to consume this BuildItem
offload_task(
consume_build_item,
build_item.pk,
quantity,
notes=notes,
user=request.user if request else None,
user_id=request.user.pk if request else None,
)
# Process the provided BuildLine objects
for line in lines:
build_line = line['build_line']
# In this case, perform full consumption of all allocated stock
for item in build_line.allocations.all():
# If the build item is tracked into an output, we do not consume now
# Instead, it gets consumed when the output is completed
if item.install_into:
continue
item.complete_allocation(
quantity=item.quantity,
notes=notes,
user=request.user if request else None,
)
# Offload a background task to consume this BuildLine
offload_task(
consume_build_line,
build_line.pk,
notes=notes,
user_id=request.user.pk if request else None,
)

View File

@@ -39,6 +39,51 @@ def auto_allocate_build(build_id: int, **kwargs):
build_order.auto_allocate_stock(**kwargs)
@tracer.start_as_current_span('consume_build_item')
def consume_build_item(
item_id: str, quantity, notes: str = '', user_id: int | None = None
):
"""Consume stock against a particular BuildOrderLineItem allocation."""
from build.models import BuildItem
item = BuildItem.objects.filter(pk=item_id).first()
if not item:
logger.warning(
'Could not consume stock for BuildItem <%s> - BuildItem does not exist',
item_id,
)
return
item.complete_allocation(
quantity=quantity,
notes=notes,
user=User.objects.filter(pk=user_id).first() if user_id else None,
)
@tracer.start_as_current_span('consume_build_line')
def consume_build_line(line_id: int, notes: str = '', user_id: int | None = None):
"""Consume stock against a particular BuildOrderLineItem."""
from build.models import BuildLine
line_item = BuildLine.objects.filter(pk=line_id).first()
if not line_item:
logger.warning(
'Could not consume stock for LineItem <%s> - LineItem does not exist',
line_id,
)
return
for item in line_item.allocations.all():
item.complete_allocation(
quantity=item.quantity,
notes=notes,
user=User.objects.filter(pk=user_id).first() if user_id else None,
)
@tracer.start_as_current_span('complete_build_allocations')
def complete_build_allocations(build_id: int, user_id: int):
"""Complete build allocations for a specified BuildOrder."""

View File

@@ -814,7 +814,7 @@ export function useConsumeBuildItemsForm({
url: ApiEndpoints.build_order_consume,
pk: buildId,
title: t`Consume Stock`,
successMessage: t`Stock items consumed`,
successMessage: t`Stock items scheduled to be consumed`,
onFormSuccess: onFormSuccess,
size: '80%',
fields: consumeFields,
@@ -915,7 +915,7 @@ export function useConsumeBuildLinesForm({
url: ApiEndpoints.build_order_consume,
pk: buildId,
title: t`Consume Stock`,
successMessage: t`Stock items consumed`,
successMessage: t`Stock items scheduled to be consumed`,
onFormSuccess: onFormSuccess,
fields: consumeFields,
initialData: {