From a6be0b32c6a660c83698c476d0659b991212528e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 17 May 2022 23:48:58 +1000 Subject: [PATCH] Add unit tests for exporting SalesOrder data --- InvenTree/InvenTree/api_tester.py | 12 ++-- InvenTree/order/admin.py | 6 ++ InvenTree/order/api.py | 4 +- InvenTree/order/test_api.py | 93 +++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 8 deletions(-) diff --git a/InvenTree/InvenTree/api_tester.py b/InvenTree/InvenTree/api_tester.py index 1fa2816653..9dde7c0f52 100644 --- a/InvenTree/InvenTree/api_tester.py +++ b/InvenTree/InvenTree/api_tester.py @@ -184,7 +184,7 @@ class InvenTreeAPITestCase(APITestCase): # Check that the response is of the correct type if not isinstance(response, StreamingHttpResponse): raise ValueError("Response is not a StreamingHttpResponse object as expected") - + # Extract filename disposition = response.headers['Content-Disposition'] @@ -230,24 +230,24 @@ class InvenTreeAPITestCase(APITestCase): headers = row else: rows.append(row) - + if required_cols is not None: for col in required_cols: self.assertIn(col, headers) - + if excluded_cols is not None: for col in excluded_cols: self.assertNotIn(col, headers) - + if required_rows is not None: self.assertEqual(len(rows), required_rows) - + # Return the file data as a list of dict items, based on the headers data = [] for row in rows: entry = {} - + for idx, col in enumerate(headers): entry[col] = row[idx] diff --git a/InvenTree/order/admin.py b/InvenTree/order/admin.py index eaeebff04d..ac74a004e3 100644 --- a/InvenTree/order/admin.py +++ b/InvenTree/order/admin.py @@ -105,6 +105,9 @@ class PurchaseOrderResource(ModelResource): model = PurchaseOrder skip_unchanged = True clean_model_instances = True + exclude = [ + 'metadata', + ] class PurchaseOrderLineItemResource(ModelResource): @@ -147,6 +150,9 @@ class SalesOrderResource(ModelResource): model = SalesOrder skip_unchanged = True clean_model_instances = True + exclude = [ + 'metadata', + ] class SalesOrderLineItemResource(ModelResource): diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index e65463d55c..2a9c3b99d2 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -667,9 +667,9 @@ class SalesOrderList(APIDownloadMixin, generics.ListCreateAPIView): outstanding = str2bool(outstanding) if outstanding: - queryset = queryset.filter(status__in=models.SalesOrderStatus.OPEN) + queryset = queryset.filter(status__in=SalesOrderStatus.OPEN) else: - queryset = queryset.exclude(status__in=models.SalesOrderStatus.OPEN) + queryset = queryset.exclude(status__in=SalesOrderStatus.OPEN) # Filter by 'overdue' status overdue = params.get('overdue', None) diff --git a/InvenTree/order/test_api.py b/InvenTree/order/test_api.py index 76aa8670a4..1a044c9b46 100644 --- a/InvenTree/order/test_api.py +++ b/InvenTree/order/test_api.py @@ -2,6 +2,8 @@ Tests for the Order API """ +import io + from datetime import datetime, timedelta from rest_framework import status @@ -908,6 +910,97 @@ class SalesOrderTest(OrderTest): self.assertEqual(order.get_metadata('xyz'), 'abc') +class SalesOrderDownloadTest(OrderTest): + """Unit tests for downloading SalesOrder data via the API endpoint""" + + def test_download_fail(self): + """Test that downloading without the 'export' option fails""" + + url = reverse('api-so-list') + + with self.assertRaises(ValueError): + self.download_file(url, {}, expected_code=200) + + def test_download_xls(self): + url = reverse('api-so-list') + + # Download .xls file + fo = self.download_file( + url, + { + 'export': 'xls', + }, + expected_code=200, + expected_fn='InvenTree_SalesOrders.xls', + ) + + self.assertTrue(isinstance(fo, io.BytesIO)) + + def test_download_csv(self): + + url = reverse('api-so-list') + + required_cols = [ + 'line_items', + 'id', + 'reference', + 'customer', + 'status', + 'shipment_date', + 'notes', + 'description', + ] + + excluded_cols = [ + 'metadata' + ] + + # Download .xls file + with self.download_file( + url, + { + 'export': 'csv', + }, + expected_code=200, + expected_fn='InvenTree_SalesOrders.csv', + decode=True + ) as fo: + + data = self.process_csv( + fo, + required_cols=required_cols, + excluded_cols=excluded_cols, + required_rows=models.SalesOrder.objects.count() + ) + + for line in data: + + order = models.SalesOrder.objects.get(pk=line['id']) + + self.assertEqual(line['description'], order.description) + self.assertEqual(line['status'], str(order.status)) + + # Download only outstanding sales orders + with self.download_file( + url, + { + 'export': 'tsv', + 'outstanding': True, + }, + expected_code=200, + expected_fn='InvenTree_SalesOrders.tsv', + decode=True, + ) as fo: + + self.process_csv( + fo, + required_cols=required_cols, + excluded_cols=excluded_cols, + required_rows=models.SalesOrder.objects.filter(status__in=SalesOrderStatus.OPEN).count(), + delimiter='\t', + ) + + class SalesOrderAllocateTest(OrderTest): """ Unit tests for allocating stock items against a SalesOrder