From 1b65fbad2c3f6d074b2704ca9e94e4ab64a637cd Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 24 Aug 2021 11:42:08 +1000 Subject: [PATCH] Update unit tests - Found some bugs too, thanks unit tests! --- InvenTree/order/api.py | 33 ++++++++++-------- InvenTree/order/serializers.py | 6 +++- InvenTree/order/test_api.py | 64 ++++++++++++++++++++++++++++++++-- 3 files changed, 86 insertions(+), 17 deletions(-) diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index 648a4f4417..f2b3879e30 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -240,9 +240,13 @@ class POReceive(generics.CreateAPIView): Returns the PurchaseOrder associated with this API endpoint """ - order = PurchaseOrder.objects.get(pk=self.kwargs['pk']) + pk = self.kwargs.get('pk', None) - return order + if pk is None: + return None + else: + order = PurchaseOrder.objects.get(pk=self.kwargs['pk']) + return order def create(self, request, *args, **kwargs): @@ -282,23 +286,24 @@ class POReceive(generics.CreateAPIView): # Check if the location is not specified for any particular item for item in items: - supplier_part = item['supplier_part'] - - # Location specified for this part - item_location = item['location'] - - if not item_location: - - # Both item_location and location are not specified - if not location: - raise ValidationError({ - 'location': _("Destination location must be specified"), - }) + 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'], diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py index 2b3da3f87d..881a0940c4 100644 --- a/InvenTree/order/serializers.py +++ b/InvenTree/order/serializers.py @@ -187,10 +187,13 @@ class POLineItemReceiveSerializer(serializers.Serializer): if item.order != self.context['order']: raise ValidationError(_('Line item does not match purchase order')) + return item + location = serializers.PrimaryKeyRelatedField( queryset=stock.models.StockLocation.objects.all(), many=False, allow_null=True, + required=False, label=_('Location'), help_text=_('Select destination location for received items'), ) @@ -210,8 +213,9 @@ class POLineItemReceiveSerializer(serializers.Serializer): class Meta: fields = [ - 'supplier_part', + 'line_item', 'location', + 'quantity', 'status', ] diff --git a/InvenTree/order/test_api.py b/InvenTree/order/test_api.py index 0074442930..26f1249cf4 100644 --- a/InvenTree/order/test_api.py +++ b/InvenTree/order/test_api.py @@ -2,7 +2,6 @@ Tests for the Order API """ -from InvenTree.stock.models import StockItem from datetime import datetime, timedelta from rest_framework import status @@ -10,8 +9,11 @@ from rest_framework import status from django.urls import reverse from InvenTree.api_tester import InvenTreeAPITestCase +from InvenTree.status_codes import PurchaseOrderStatus -from .models import PurchaseOrder, SalesOrder +from stock.models import StockItem + +from .models import PurchaseOrder, PurchaseOrderLineItem, SalesOrder class OrderTest(InvenTreeAPITestCase): @@ -217,6 +219,11 @@ class PurchaseOrderReceiveTest(OrderTest): # Number of stock items which exist at the start of each test self.n = StockItem.objects.count() + # Mark the order as "placed" so we can receive line items + order = PurchaseOrder.objects.get(pk=1) + order.status = PurchaseOrderStatus.PLACED + order.save() + def test_empty(self): """ Test without any POST data @@ -325,6 +332,59 @@ class PurchaseOrderReceiveTest(OrderTest): # No new stock items have been created self.assertEqual(self.n, StockItem.objects.count()) + def test_valid(self): + """ + Test receipt of valid data + """ + + line_1 = PurchaseOrderLineItem.objects.get(pk=1) + line_2 = PurchaseOrderLineItem.objects.get(pk=2) + + self.assertEqual(StockItem.objects.filter(supplier_part=line_1.part).count(), 0) + self.assertEqual(StockItem.objects.filter(supplier_part=line_2.part).count(), 0) + + self.assertEqual(line_1.received, 0) + self.assertEqual(line_2.received, 50) + + # Receive two separate line items against this order + data = self.post( + self.url, + { + 'items': [ + { + 'line_item': 1, + 'quantity': 50, + }, + { + 'line_item': 2, + 'quantity': 200, + 'location': 2, # Explicit location + } + ], + 'location': 1, # Default location + }, + ).data + + # There should be two newly created stock items + self.assertEqual(self.n + 2, StockItem.objects.count()) + + line_1 = PurchaseOrderLineItem.objects.get(pk=1) + line_2 = PurchaseOrderLineItem.objects.get(pk=2) + + self.assertEqual(line_1.received, 50) + self.assertEqual(line_2.received, 250) + + stock_1 = StockItem.objects.filter(supplier_part=line_1.part) + stock_2 = StockItem.objects.filter(supplier_part=line_2.part) + + # 1 new stock item created for each supplier part + self.assertEqual(stock_1.count(), 1) + self.assertEqual(stock_2.count(), 1) + + # Different location for each received item + self.assertEqual(stock_1.last().location.pk, 1) + self.assertEqual(stock_2.last().location.pk, 2) + class SalesOrderTest(OrderTest): """