From 2186a66465c6895a15c24070ca94f7b795936723 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 22 Feb 2021 22:05:20 +1100 Subject: [PATCH] Build: Filter by parent or ancestor in API - Add unit testing --- InvenTree/build/api.py | 22 +++++ InvenTree/build/test_api.py | 163 ++++++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 InvenTree/build/test_api.py diff --git a/InvenTree/build/api.py b/InvenTree/build/api.py index d76c0a4b51..cb6b3f6b2b 100644 --- a/InvenTree/build/api.py +++ b/InvenTree/build/api.py @@ -56,6 +56,28 @@ class BuildList(generics.ListCreateAPIView): params = self.request.query_params + # Filter by "parent" + parent = params.get('parent', None) + + if parent is not None: + queryset = queryset.filter(parent=parent) + + # Filter by "ancestor" builds + ancestor = params.get('ancestor', None) + + if ancestor is not None: + try: + ancestor = Build.objects.get(pk=ancestor) + + descendants = ancestor.get_descendants(include_self=True) + + queryset = queryset.filter( + parent__pk__in=[b.pk for b in descendants] + ) + + except (ValueError, Build.DoesNotExist): + pass + # Filter by build status? status = params.get('status', None) diff --git a/InvenTree/build/test_api.py b/InvenTree/build/test_api.py new file mode 100644 index 0000000000..41b09c8e08 --- /dev/null +++ b/InvenTree/build/test_api.py @@ -0,0 +1,163 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from datetime import datetime, timedelta + +from rest_framework.test import APITestCase +from rest_framework import status + +from django.urls import reverse +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group + +from part.models import Part +from build.models import Build + +from InvenTree.status_codes import BuildStatus + + +class BuildAPITest(APITestCase): + """ + Series of tests for the Build DRF API + """ + + fixtures = [ + 'category', + 'part', + 'location', + 'bom', + 'build', + ] + + def setUp(self): + # Create a user for auth + user = get_user_model() + + self.user = user.objects.create_user( + username='testuser', + email='test@testing.com', + password='password' + ) + + # Put the user into a group with the correct permissions + group = Group.objects.create(name='mygroup') + self.user.groups.add(group) + + # Give the group *all* the permissions! + for rule in group.rule_sets.all(): + rule.can_view = True + rule.can_change = True + rule.can_add = True + rule.can_delete = True + + rule.save() + + group.save() + + self.client.login(username='testuser', password='password') + + +class BuildListTest(BuildAPITest): + """ + Tests for the BuildOrder LIST API + """ + + url = reverse('api-build-list') + + def get(self, status=200, data={}): + + response = self.client.get(self.url, data, format='json') + + self.assertEqual(response.status_code, status) + + return response.data + + def test_get_all_builds(self): + """ + Retrieve *all* builds via the API + """ + + builds = self.get() + + self.assertEqual(len(builds), 5) + + builds = self.get(data={'active': True}) + self.assertEqual(len(builds), 1) + + builds = self.get(data={'status': BuildStatus.COMPLETE}) + self.assertEqual(len(builds), 4) + + builds = self.get(data={'overdue': False}) + self.assertEqual(len(builds), 5) + + builds = self.get(data={'overdue': True}) + self.assertEqual(len(builds), 0) + + def test_overdue(self): + """ + Create a new build, in the past + """ + + in_the_past = datetime.now().date() - timedelta(days=50) + + part = Part.objects.get(pk=50) + + build = Build.objects.create( + part=part, + quantity=10, + title='Just some thing', + status=BuildStatus.PRODUCTION, + target_date=in_the_past + ) + + builds = self.get(data={'overdue': True}) + + self.assertEqual(len(builds), 1) + + def test_sub_builds(self): + """ + Test the build / sub-build relationship + """ + + parent = Build.objects.get(pk=5) + + part = Part.objects.get(pk=50) + + n = Build.objects.count() + + # Make some sub builds + for i in range(5): + Build.objects.create( + part=part, + quantity=10, + reference=f"build-000{i}", + title=f"Sub build {i}", + parent=parent + ) + + # And some sub-sub builds + for sub_build in Build.objects.filter(parent=parent): + + for i in range(3): + Build.objects.create( + part=part, + reference=f"{sub_build.reference}-00{i}-sub", + quantity=40, + title=f"sub sub build {i}", + parent=sub_build + ) + + # 20 new builds should have been created! + self.assertEqual(Build.objects.count(), (n + 20)) + + Build.objects.rebuild() + + # Search by parent + builds = self.get(data={'parent': parent.pk}) + + self.assertEqual(len(builds), 5) + + # Search by ancestor + builds = self.get(data={'ancestor': parent.pk}) + + self.assertEqual(len(builds), 20)