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:
parent
44d9484715
commit
198a39a33c
@ -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
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user