diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index b837b3da59..9331cdf215 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -43,7 +43,7 @@ class TreeSerializer(views.APIView): 'pk': item.id, 'text': item.name, 'href': item.get_absolute_url(), - 'tags': [item.item_count], + 'tags': [item.stock_item_count], } if item.has_children: @@ -66,7 +66,7 @@ class TreeSerializer(views.APIView): for item in top_items: nodes.append(self.itemToJson(item)) - top_count += item.item_count + top_count += item.stock_item_count top = { 'pk': None, diff --git a/InvenTree/stock/fixtures/location.yaml b/InvenTree/stock/fixtures/location.yaml index fdc11f8fa1..f34490af29 100644 --- a/InvenTree/stock/fixtures/location.yaml +++ b/InvenTree/stock/fixtures/location.yaml @@ -5,12 +5,14 @@ fields: name: 'Home' description: 'My house' + - model: stock.stocklocation pk: 2 fields: name: 'Bathroom' description: 'Where I keep my bath' parent: 1 + - model: stock.stocklocation pk: 3 fields: @@ -23,18 +25,21 @@ fields: name: 'Office' description: 'Place of work' + - model: stock.stocklocation pk: 5 fields: name: 'Drawer_1' description: 'In my desk' parent: 4 + - model: stock.stocklocation pk: 6 fields: name: 'Drawer_2' description: 'Also in my desk' parent: 4 + - model: stock.stocklocation pk: 7 fields: diff --git a/InvenTree/stock/fixtures/stock.yaml b/InvenTree/stock/fixtures/stock.yaml index 18e0260e27..96e0a3ab72 100644 --- a/InvenTree/stock/fixtures/stock.yaml +++ b/InvenTree/stock/fixtures/stock.yaml @@ -17,6 +17,7 @@ # 1234 2K2 resistors in 'Drawer_1' - model: stock.stockitem + pk: 1234 fields: part: 3 location: 5 @@ -24,18 +25,22 @@ # Some widgets in drawer 3 - model: stock.stockitem + pk: 100 fields: part: 25 location: 7 quantity: 10 + delete_on_deplete: False - model: stock.stockitem + pk: 101 fields: part: 25 location: 7 quantity: 5 - model: stock.stockitem + pk: 102 fields: part: 25 location: 7 diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index f4956d32e6..cbc64f42ab 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -53,12 +53,7 @@ class StockLocation(InvenTreeTree): """ Return the number of StockItem objects which live in or under this category """ - return len(StockItem.objects.filter(location__in=self.getUniqueChildren())) - - @property - def item_count(self): - - return self.stock_item_count + return StockItem.objects.filter(location__in=self.getUniqueChildren()).count() @receiver(pre_delete, sender=StockLocation, dispatch_uid='stocklocation_delete_log') @@ -444,9 +439,6 @@ class StockItem(models.Model): """ Remove items from stock """ - if self.quantity == 0: - return False - quantity = int(quantity) if quantity <= 0 or self.infinite: diff --git a/InvenTree/stock/tests.py b/InvenTree/stock/tests.py index 5ca6c29e40..fb1434828a 100644 --- a/InvenTree/stock/tests.py +++ b/InvenTree/stock/tests.py @@ -37,6 +37,11 @@ class StockTest(TestCase): self.assertEqual(self.home.get_absolute_url(), '/stock/location/1/') + def test_barcode(self): + barcode = self.office.format_barcode() + + self.assertIn('"name": "Office"', barcode) + def test_strings(self): it = StockItem.objects.get(pk=1) self.assertEqual(str(it), '4000 x M2x4 LPHS @ Dining Room') @@ -74,6 +79,7 @@ class StockTest(TestCase): # Drawer 3 should have three stock items self.assertEqual(self.drawer3.stock_items.count(), 3) + self.assertEqual(self.drawer3.stock_item_count, 3) def test_stock_count(self): part = Part.objects.get(pk=1) @@ -133,7 +139,44 @@ class StockTest(TestCase): self.assertEqual(it.tracking_info.count(), n) def test_partial_move(self): - pass + w1 = StockItem.objects.get(pk=100) + w2 = StockItem.objects.get(pk=101) + + q = w1.quantity + + # Move 6 of the units + self.assertTrue(w1.move(self.diningroom, 'Moved', None, quantity=6)) + self.assertEqual(w1.quantity, 6) + + # There should also be a new object still in drawer3 + self.assertEqual(StockItem.objects.filter(part=25).count(), 4) + widget = StockItem.objects.get(location=self.drawer3.id, part=25, quantity=4) + + # Try to move negative units + self.assertFalse(widget.move(self.bathroom, 'Test', None, quantity=-100)) + self.assertEqual(StockItem.objects.filter(part=25).count(), 4) + + # Try to move to a blank location + self.assertFalse(widget.move(None, 'null', None)) + + def test_split_stock(self): + # Split the 1234 x 2K2 resistors in Drawer_1 + + N = StockItem.objects.filter(part=3).count() + + stock = StockItem.objects.get(id=1234) + stock.splitStock(1000, None) + self.assertEqual(stock.quantity, 234) + + # There should be a new stock item too! + self.assertEqual(StockItem.objects.filter(part=3).count(), N + 1) + + # Try to split a negative quantity + stock.splitStock(-10, None) + self.assertEqual(StockItem.objects.filter(part=3).count(), N + 1) + + stock.splitStock(stock.quantity, None) + self.assertEqual(StockItem.objects.filter(part=3).count(), N + 1) def test_stocktake(self): # Perform stocktake @@ -168,6 +211,8 @@ class StockTest(TestCase): self.assertIn('Added', track.title) self.assertIn('Added some items', track.notes) + self.assertFalse(it.add_stock(-10, None)) + def test_take_stock(self): it = StockItem.objects.get(pk=2) n = it.quantity @@ -181,3 +226,24 @@ class StockTest(TestCase): self.assertIn('Removed', track.title) self.assertIn('Removed some items', track.notes) self.assertTrue(it.has_tracking_info) + + # Test that negative quantity does nothing + self.assertFalse(it.take_stock(-10, None)) + + def test_deplete_stock(self): + + w1 = StockItem.objects.get(pk=100) + w2 = StockItem.objects.get(pk=101) + + # Take 25 units from w1 + w1.take_stock(30, None, notes='Took 30') + + # Get from database again + w1 = StockItem.objects.get(pk=100) + self.assertEqual(w1.quantity, 0) + + # Take 25 units from w2 (will be deleted) + w2.take_stock(30, None, notes='Took 30') + + with self.assertRaises(StockItem.DoesNotExist): + w2 = StockItem.objects.get(pk=101)