2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 11:36:44 +00:00

[Refactor] Sales Order Shipment (#8249)

* Refactor serial number allocation

* Refactor API query

Note: This should be further improved, not to automatically return *all* allocation data

* Push expensive operations off to background worker

* Bump API version
This commit is contained in:
Oliver 2024-10-08 08:00:32 +11:00 committed by GitHub
parent 44d9484715
commit 198a39a33c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 64 additions and 15 deletions

View File

@ -1,14 +1,17 @@
"""InvenTree API version information."""
# InvenTree API version
INVENTREE_API_VERSION = 265
INVENTREE_API_VERSION = 266
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """
265 - 2024-10-06 : https://github.com/inventree/InvenTree/pull/8228
266 - 2024-10-07 : https://github.com/inventree/InvenTree/pull/8249
- Tweak SalesOrderShipment API for more efficient data retrieval
265 - 2024-10-07 : https://github.com/inventree/InvenTree/pull/8228
- Adds API endpoint for providing custom admin integration details for plugins
264 - 2024-10-03 : https://github.com/inventree/InvenTree/pull/8231

View File

@ -767,11 +767,15 @@ class SalesOrderLineItemMixin:
'part',
'part__stock_items',
'allocations',
'allocations__shipment',
'allocations__item__part',
'allocations__item__location',
'order',
'order__stock_items',
)
queryset = queryset.select_related('part__pricing_data')
queryset = serializers.SalesOrderLineItemSerializer.annotate_queryset(queryset)
return queryset

View File

@ -1878,16 +1878,11 @@ class SalesOrderShipment(
2. Update the "shipped" quantity of all associated line items
3. Set the "shipment_date" to now
"""
import order.tasks
# Check if the shipment can be completed (throw error if not)
self.check_can_complete()
allocations = self.allocations.all()
# Iterate through each stock item assigned to this shipment
for allocation in allocations:
# Mark the allocation as "complete"
allocation.complete_allocation(user)
# Update the "shipment" date
self.shipment_date = kwargs.get(
'shipment_date', InvenTree.helpers.current_date()
@ -1920,6 +1915,14 @@ class SalesOrderShipment(
self.save()
# Offload the "completion" of each line item to the background worker
# This may take some time, and we don't want to block the main thread
InvenTree.tasks.offload_task(
order.tasks.complete_sales_order_shipment,
shipment_id=self.pk,
user_id=user.pk if user else None,
)
trigger_event('salesordershipment.completed', id=self.pk)
def create_attachment(self, *args, **kwargs):

View File

@ -1094,10 +1094,10 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer):
# Extra detail fields
order_detail = SalesOrderSerializer(source='line.order', many=False, read_only=True)
part_detail = PartBriefSerializer(source='item.part', many=False, read_only=True)
item_detail = stock.serializers.StockItemSerializer(
item_detail = stock.serializers.StockItemSerializerBrief(
source='item', many=False, read_only=True
)
location_detail = stock.serializers.LocationSerializer(
location_detail = stock.serializers.LocationBriefSerializer(
source='item.location', many=False, read_only=True
)
customer_detail = CompanyBriefSerializer(
@ -1659,12 +1659,18 @@ class SalesOrderSerialAllocationSerializer(serializers.Serializer):
stock_items = data['stock_items']
shipment = data['shipment']
with transaction.atomic():
for stock_item in stock_items:
# Create a new SalesOrderAllocation
order.models.SalesOrderAllocation.objects.create(
allocations = []
for stock_item in stock_items:
# Create a new SalesOrderAllocation
allocations.append(
order.models.SalesOrderAllocation(
line=line_item, item=stock_item, quantity=1, shipment=shipment
)
)
with transaction.atomic():
order.models.SalesOrderAllocation.objects.bulk_create(allocations)
class SalesOrderShipmentAllocationSerializer(serializers.Serializer):

View File

@ -1,7 +1,10 @@
"""Background tasks for the 'order' app."""
import logging
from datetime import datetime, timedelta
from django.contrib.auth.models import User
from django.db import transaction
from django.utils.translation import gettext_lazy as _
import common.notifications
@ -11,6 +14,8 @@ from InvenTree.tasks import ScheduledTask, scheduled_task
from order.status_codes import PurchaseOrderStatusGroups, SalesOrderStatusGroups
from plugin.events import trigger_event
logger = logging.getLogger('inventree')
def notify_overdue_purchase_order(po: order.models.PurchaseOrder):
"""Notify users that a PurchaseOrder has just become 'overdue'."""
@ -109,3 +114,31 @@ def check_overdue_sales_orders():
for po in overdue_orders:
notify_overdue_sales_order(po)
def complete_sales_order_shipment(shipment_id: int, user_id: int) -> None:
"""Complete allocations for a pending shipment against a SalesOrder.
At this stage, the shipment is assumed to be complete,
and we need to perform the required "processing" tasks.
"""
try:
shipment = order.models.SalesOrderShipment.objects.get(pk=shipment_id)
except Exception:
# Shipping object does not exist
logger.warning(
'Failed to complete shipment - no matching SalesOrderShipment for ID <%s>',
shipment_id,
)
return
try:
user = User.objects.get(pk=user_id)
except Exception:
user = None
logger.info('Completing SalesOrderShipment <%s>', shipment)
with transaction.atomic():
for allocation in shipment.allocations.all():
allocation.complete_allocation(user=user)