From 29588ff2c5baf70562eb883da846008f20341aec Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 5 Oct 2021 11:20:43 +1100 Subject: [PATCH] Refactor the POReceive API endpoint - Lessons learned from the build allocate - Use serializer.save() directly --- InvenTree/build/tests.py | 2 +- InvenTree/order/api.py | 70 ---------------------------------- InvenTree/order/serializers.py | 42 +++++++++++++++++++- 3 files changed, 42 insertions(+), 72 deletions(-) diff --git a/InvenTree/build/tests.py b/InvenTree/build/tests.py index dc44c3c6c8..93c6bfd511 100644 --- a/InvenTree/build/tests.py +++ b/InvenTree/build/tests.py @@ -172,7 +172,7 @@ class TestBuildAPI(APITestCase): # Filter by 'part' status response = self.client.get(url, {'part': 25}, format='json') - self.assertEqual(len(response.data), 2) + self.assertEqual(len(response.data), 1) # Filter by an invalid part response = self.client.get(url, {'part': 99999}, format='json') diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index ab6c4d7c0b..fc19610320 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -252,76 +252,6 @@ class POReceive(generics.CreateAPIView): return order - def create(self, request, *args, **kwargs): - - # Which purchase order are we receiving against? - self.order = self.get_order() - - # Validate the serialized data - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - - # Receive the line items - try: - self.receive_items(serializer) - except DjangoValidationError as exc: - # Re-throw a django error as a DRF error - raise ValidationError(detail=serializers.as_serializer_error(exc)) - - headers = self.get_success_headers(serializer.data) - - return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) - - @transaction.atomic - def receive_items(self, serializer): - """ - Receive the items - - At this point, much of the heavy lifting has been done for us by DRF serializers! - - We have a list of "items", each a dict which contains: - - line_item: A PurchaseOrderLineItem matching this order - - location: A destination location - - quantity: A validated numerical quantity - - status: The status code for the received item - """ - - data = serializer.validated_data - - location = data['location'] - - items = data['items'] - - # Check if the location is not specified for any particular item - for item in items: - - line = item['line_item'] - - if not item.get('location', None): - # If a global location is specified, use that - item['location'] = location - - if not item['location']: - # The line item specifies a location? - item['location'] = line.get_destination() - - if not item['location']: - raise ValidationError({ - 'location': _("Destination location must be specified"), - }) - - # Now we can actually receive the items - for item in items: - - self.order.receive_line_item( - item['line_item'], - item['location'], - item['quantity'], - self.request.user, - status=item['status'], - barcode=item.get('barcode', ''), - ) - class POLineItemList(generics.ListCreateAPIView): """ API endpoint for accessing a list of POLineItem objects diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py index 0a93510c6f..9600e2acaf 100644 --- a/InvenTree/order/serializers.py +++ b/InvenTree/order/serializers.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from django.db import models +from django.db import models, transaction from django.db.models import Case, When, Value from django.db.models import BooleanField, ExpressionWrapper, F @@ -301,6 +301,46 @@ class POReceiveSerializer(serializers.Serializer): return data + def save(self): + + data = self.validated_data + + order = self.context['order'] + + items = data['items'] + location = data.get('location', None) + + # Check if the location is not specified for any particular item + for item in items: + + line = item['line_item'] + + if not item.get('location', None): + # If a global location is specified, use that + item['location'] = location + + if not item['location']: + # The line item specifies a location? + item['location'] = line.get_destination() + + if not item['location']: + raise ValidationError({ + 'location': _("Destination location must be specified"), + }) + + # Now we can actually receive the items into stock + with transaction.atomic(): + for item in items: + order.receive_line_item( + item['line_item'], + item['location'], + item['quantity'], + self.request.user, + status=item['status'], + barcode=item.get('barcode', ''), + ) + + class Meta: fields = [ 'items',