From 82541ede32efa2778c48e9bb7e3b3456021b9df7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 4 May 2022 22:49:21 +1000 Subject: [PATCH] More unit tests - BuildOrderCancel - StockItemInstall - StockItemUninstall --- InvenTree/build/test_api.py | 17 ++++++- InvenTree/part/models.py | 15 ++---- InvenTree/part/test_bom_item.py | 2 +- InvenTree/stock/test_api.py | 83 +++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 12 deletions(-) diff --git a/InvenTree/build/test_api.py b/InvenTree/build/test_api.py index 8c9d0fe7e1..a54a92dda8 100644 --- a/InvenTree/build/test_api.py +++ b/InvenTree/build/test_api.py @@ -122,7 +122,7 @@ class BuildAPITest(InvenTreeAPITestCase): super().setUp() -class BuildOutputCompleteTest(BuildAPITest): +class BuildTest(BuildAPITest): """ Unit testing for the build complete API endpoint """ @@ -290,6 +290,21 @@ class BuildOutputCompleteTest(BuildAPITest): # Build should have been marked as complete self.assertTrue(self.build.is_complete) + def test_cancel(self): + """ Test that we can cancel a BuildOrder via the API """ + + bo = Build.objects.get(pk=1) + + url = reverse('api-build-cancel', kwargs={'pk': bo.pk}) + + self.assertEqual(bo.status, BuildStatus.PENDING) + + self.post(url, {}, expected_code=201) + + bo.refresh_from_db() + + self.assertEqual(bo.status, BuildStatus.CANCELLED) + class BuildAllocationTest(BuildAPITest): """ diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 46b2154c43..de2616b772 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -491,7 +491,7 @@ class Part(MPTTModel): def __str__(self): return f"{self.full_name} - {self.description}" - def get_parts_in_bom(self): + def get_parts_in_bom(self, **kwargs): """ Return a list of all parts in the BOM for this part. Takes into account substitutes, variant parts, and inherited BOM items @@ -499,27 +499,22 @@ class Part(MPTTModel): parts = set() - for bom_item in self.get_bom_items(): + for bom_item in self.get_bom_items(**kwargs): for part in bom_item.get_valid_parts_for_allocation(): parts.add(part) return parts - def check_if_part_in_bom(self, other_part): + def check_if_part_in_bom(self, other_part, **kwargs): """ - Check if the other_part is in the BOM for this part. + Check if the other_part is in the BOM for *this* part. Note: - Accounts for substitute parts - Accounts for variant BOMs """ - for bom_item in self.get_bom_items(): - if other_part in bom_item.get_valid_parts_for_allocation(): - return True - - # No matches found - return False + return other_part in self.get_parts_in_bom(**kwargs) def check_add_to_bom(self, parent, raise_error=False, recursive=True): """ diff --git a/InvenTree/part/test_bom_item.py b/InvenTree/part/test_bom_item.py index 88548f3cf7..0789ed08c3 100644 --- a/InvenTree/part/test_bom_item.py +++ b/InvenTree/part/test_bom_item.py @@ -43,7 +43,7 @@ class BomItemTest(TestCase): self.assertIn(self.orphan, parts) - # TODO: Tests for multi-level BOMs + self.assertTrue(self.bob.check_if_part_in_bom(self.orphan)) def test_used_in(self): self.assertEqual(self.bob.used_in_count, 1) diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index 7f94c6dedf..1f040b008d 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -29,6 +29,7 @@ class StockAPITestCase(InvenTreeAPITestCase): fixtures = [ 'category', 'part', + 'bom', 'company', 'location', 'supplier_part', @@ -643,6 +644,88 @@ class StockItemTest(StockAPITestCase): data = self.get(url).data self.assertEqual(data['purchase_price_currency'], 'NZD') + def test_install(self): + """ Test that stock item can be installed into antoher item, via the API """ + + # Select the "parent" stock item + parent_part = part.models.Part.objects.get(pk=100) + + item = StockItem.objects.create( + part=parent_part, + serial='12345688-1230', + quantity=1, + ) + + sub_part = part.models.Part.objects.get(pk=50) + sub_item = StockItem.objects.create( + part=sub_part, + serial='xyz-123', + quantity=1, + ) + + n_entries = sub_item.tracking_info.count() + + self.assertIsNone(sub_item.belongs_to) + + url = reverse('api-stock-item-install', kwargs={'pk': item.pk}) + + # Try to install an item that is *not* in the BOM for this part! + response = self.post( + url, + { + 'stock_item': 520, + 'note': 'This should fail, as Item #522 is not in the BOM', + }, + expected_code=400 + ) + + self.assertIn('Selected part is not in the Bill of Materials', str(response.data)) + + # Now, try to install an item which *is* in the BOM for the parent part + response = self.post( + url, + { + 'stock_item': sub_item.pk, + 'note': "This time, it should be good!", + }, + expected_code=201, + ) + + sub_item.refresh_from_db() + + self.assertEqual(sub_item.belongs_to, item) + + self.assertEqual(n_entries + 1, sub_item.tracking_info.count()) + + # Try to install again - this time, should fail because the StockItem is not available! + response = self.post( + url, + { + 'stock_item': sub_item.pk, + 'note': 'Expectation: failure!', + }, + expected_code=400, + ) + + self.assertIn('Stock item is unavailable', str(response.data)) + + # Now, try to uninstall via the API + + url = reverse('api-stock-item-uninstall', kwargs={'pk': sub_item.pk}) + + self.post( + url, + { + 'location': 1, + }, + expected_code=201, + ) + + sub_item.refresh_from_db() + + self.assertIsNone(sub_item.belongs_to) + self.assertEqual(sub_item.location.pk, 1) + class StocktakeTest(StockAPITestCase): """