mirror of
https://github.com/inventree/InvenTree.git
synced 2025-11-30 09:20:03 +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:
@@ -39,6 +39,7 @@ from InvenTree.serializers import (
|
|||||||
NotesFieldMixin,
|
NotesFieldMixin,
|
||||||
enable_filter,
|
enable_filter,
|
||||||
)
|
)
|
||||||
|
from InvenTree.tasks import offload_task
|
||||||
from stock.generators import generate_batch_code
|
from stock.generators import generate_batch_code
|
||||||
from stock.models import StockItem, StockLocation
|
from stock.models import StockItem, StockLocation
|
||||||
from stock.serializers import (
|
from stock.serializers import (
|
||||||
@@ -51,6 +52,7 @@ from users.serializers import OwnerSerializer, UserSerializer
|
|||||||
|
|
||||||
from .models import Build, BuildItem, BuildLine
|
from .models import Build, BuildItem, BuildLine
|
||||||
from .status_codes import BuildStatus
|
from .status_codes import BuildStatus
|
||||||
|
from .tasks import consume_build_item, consume_build_line
|
||||||
|
|
||||||
|
|
||||||
class BuildSerializer(
|
class BuildSerializer(
|
||||||
@@ -1845,12 +1847,14 @@ class BuildConsumeSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self):
|
def save(self):
|
||||||
"""Perform the stock consumption step."""
|
"""Perform the stock consumption step."""
|
||||||
data = self.validated_data
|
data = self.validated_data
|
||||||
request = self.context.get('request')
|
request = self.context.get('request')
|
||||||
notes = data.get('notes', '')
|
notes = data.get('notes', '')
|
||||||
|
|
||||||
|
# We may be passed either a list of BuildItem or BuildLine instances
|
||||||
items = data.get('items', [])
|
items = data.get('items', [])
|
||||||
lines = data.get('lines', [])
|
lines = data.get('lines', [])
|
||||||
|
|
||||||
@@ -1865,25 +1869,23 @@ class BuildConsumeSerializer(serializers.Serializer):
|
|||||||
# Instead, it gets consumed when the output is completed
|
# Instead, it gets consumed when the output is completed
|
||||||
continue
|
continue
|
||||||
|
|
||||||
build_item.complete_allocation(
|
# Offload a background task to consume this BuildItem
|
||||||
quantity=quantity,
|
offload_task(
|
||||||
|
consume_build_item,
|
||||||
|
build_item.pk,
|
||||||
|
quantity,
|
||||||
notes=notes,
|
notes=notes,
|
||||||
user=request.user if request else None,
|
user_id=request.user.pk if request else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Process the provided BuildLine objects
|
# Process the provided BuildLine objects
|
||||||
for line in lines:
|
for line in lines:
|
||||||
build_line = line['build_line']
|
build_line = line['build_line']
|
||||||
|
|
||||||
# In this case, perform full consumption of all allocated stock
|
# Offload a background task to consume this BuildLine
|
||||||
for item in build_line.allocations.all():
|
offload_task(
|
||||||
# If the build item is tracked into an output, we do not consume now
|
consume_build_line,
|
||||||
# Instead, it gets consumed when the output is completed
|
build_line.pk,
|
||||||
if item.install_into:
|
notes=notes,
|
||||||
continue
|
user_id=request.user.pk if request else None,
|
||||||
|
)
|
||||||
item.complete_allocation(
|
|
||||||
quantity=item.quantity,
|
|
||||||
notes=notes,
|
|
||||||
user=request.user if request else None,
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -39,6 +39,51 @@ def auto_allocate_build(build_id: int, **kwargs):
|
|||||||
build_order.auto_allocate_stock(**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')
|
@tracer.start_as_current_span('complete_build_allocations')
|
||||||
def complete_build_allocations(build_id: int, user_id: int):
|
def complete_build_allocations(build_id: int, user_id: int):
|
||||||
"""Complete build allocations for a specified BuildOrder."""
|
"""Complete build allocations for a specified BuildOrder."""
|
||||||
|
|||||||
@@ -814,7 +814,7 @@ export function useConsumeBuildItemsForm({
|
|||||||
url: ApiEndpoints.build_order_consume,
|
url: ApiEndpoints.build_order_consume,
|
||||||
pk: buildId,
|
pk: buildId,
|
||||||
title: t`Consume Stock`,
|
title: t`Consume Stock`,
|
||||||
successMessage: t`Stock items consumed`,
|
successMessage: t`Stock items scheduled to be consumed`,
|
||||||
onFormSuccess: onFormSuccess,
|
onFormSuccess: onFormSuccess,
|
||||||
size: '80%',
|
size: '80%',
|
||||||
fields: consumeFields,
|
fields: consumeFields,
|
||||||
@@ -915,7 +915,7 @@ export function useConsumeBuildLinesForm({
|
|||||||
url: ApiEndpoints.build_order_consume,
|
url: ApiEndpoints.build_order_consume,
|
||||||
pk: buildId,
|
pk: buildId,
|
||||||
title: t`Consume Stock`,
|
title: t`Consume Stock`,
|
||||||
successMessage: t`Stock items consumed`,
|
successMessage: t`Stock items scheduled to be consumed`,
|
||||||
onFormSuccess: onFormSuccess,
|
onFormSuccess: onFormSuccess,
|
||||||
fields: consumeFields,
|
fields: consumeFields,
|
||||||
initialData: {
|
initialData: {
|
||||||
|
|||||||
Reference in New Issue
Block a user