mirror of
https://github.com/inventree/InvenTree.git
synced 2026-07-17 20:23:50 +00:00
Uninstall fix (#12378)
* Prevent uninstall into structural location * Regression tests
This commit is contained in:
@@ -1760,6 +1760,11 @@ class StockItem(
|
|||||||
if self.belongs_to is None:
|
if self.belongs_to is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if location and location.structural:
|
||||||
|
raise ValidationError({
|
||||||
|
'location': _('Cannot assign stock to structural location')
|
||||||
|
})
|
||||||
|
|
||||||
# Add a transaction note to the parent item
|
# Add a transaction note to the parent item
|
||||||
self.belongs_to.add_tracking_entry(
|
self.belongs_to.add_tracking_entry(
|
||||||
StockHistoryCode.REMOVED_CHILD_ITEM,
|
StockHistoryCode.REMOVED_CHILD_ITEM,
|
||||||
|
|||||||
@@ -938,6 +938,15 @@ class UninstallStockItemSerializer(serializers.Serializer):
|
|||||||
allow_blank=True,
|
allow_blank=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def validate_location(self, location):
|
||||||
|
"""Validate the provided location."""
|
||||||
|
if location and location.structural:
|
||||||
|
raise ValidationError(
|
||||||
|
_('Structural locations cannot be assigned stock items')
|
||||||
|
)
|
||||||
|
|
||||||
|
return location
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""Uninstall stock item."""
|
"""Uninstall stock item."""
|
||||||
item = self.context.get('item')
|
item = self.context.get('item')
|
||||||
|
|||||||
@@ -1977,6 +1977,20 @@ class StockItemTest(StockAPITestCase):
|
|||||||
|
|
||||||
url = reverse('api-stock-item-uninstall', kwargs={'pk': sub_item.pk})
|
url = reverse('api-stock-item-uninstall', kwargs={'pk': sub_item.pk})
|
||||||
|
|
||||||
|
# An uninstalled item cannot be moved into a structural location
|
||||||
|
structural = StockLocation.objects.create(
|
||||||
|
name='Structural location', structural=True
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.post(url, {'location': structural.pk}, expected_code=400)
|
||||||
|
|
||||||
|
self.assertIn(
|
||||||
|
'Structural locations cannot be assigned stock items', str(response.data)
|
||||||
|
)
|
||||||
|
|
||||||
|
sub_item.refresh_from_db()
|
||||||
|
self.assertEqual(sub_item.belongs_to, item)
|
||||||
|
|
||||||
self.post(url, {'location': 1}, expected_code=201)
|
self.post(url, {'location': 1}, expected_code=201)
|
||||||
|
|
||||||
sub_item.refresh_from_db()
|
sub_item.refresh_from_db()
|
||||||
|
|||||||
@@ -351,6 +351,38 @@ class StockTest(StockTestBase):
|
|||||||
stock.splitStock(stock.quantity, None, self.user)
|
stock.splitStock(stock.quantity, None, self.user)
|
||||||
self.assertEqual(StockItem.objects.filter(part=3).count(), n + 1)
|
self.assertEqual(StockItem.objects.filter(part=3).count(), n + 1)
|
||||||
|
|
||||||
|
def test_uninstall_into_structural_location(self):
|
||||||
|
"""Test that an item cannot be uninstalled into a structural location."""
|
||||||
|
parent = StockItem.objects.get(pk=1)
|
||||||
|
|
||||||
|
item = StockItem.objects.get(pk=2)
|
||||||
|
item.belongs_to = parent
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
n_entries = item.tracking_info.count()
|
||||||
|
n_parent_entries = parent.tracking_info.count()
|
||||||
|
|
||||||
|
structural = StockLocation.objects.create(
|
||||||
|
name='Structural location', structural=True
|
||||||
|
)
|
||||||
|
|
||||||
|
with self.assertRaises(ValidationError):
|
||||||
|
item.uninstall_into_location(structural, self.user, 'Uninstalling')
|
||||||
|
|
||||||
|
# The item remains installed, with no location change or tracking entries
|
||||||
|
item.refresh_from_db()
|
||||||
|
self.assertEqual(item.belongs_to, parent)
|
||||||
|
self.assertNotEqual(item.location, structural)
|
||||||
|
self.assertEqual(item.tracking_info.count(), n_entries)
|
||||||
|
self.assertEqual(parent.tracking_info.count(), n_parent_entries)
|
||||||
|
|
||||||
|
# Uninstalling into a non-structural location is still permitted
|
||||||
|
item.uninstall_into_location(self.drawer2, self.user, 'Uninstalling')
|
||||||
|
|
||||||
|
item.refresh_from_db()
|
||||||
|
self.assertIsNone(item.belongs_to)
|
||||||
|
self.assertEqual(item.location, self.drawer2)
|
||||||
|
|
||||||
def test_child_items(self):
|
def test_child_items(self):
|
||||||
"""Test the 'children' reverse relation and 'child_count' property.
|
"""Test the 'children' reverse relation and 'child_count' property.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user