mirror of
https://github.com/inventree/InvenTree.git
synced 2026-05-06 09:43:38 +00:00
Delete output check (#11881)
* Allow deletion of serialized build output - If calling "delete_output" on a BuildOrder - Only will delete an in_production output - Ignore the global setting in this case Co-authored-by: Copilot <copilot@github.com> * Add unit test Co-authored-by: Copilot <copilot@github.com> --------- Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -1033,7 +1033,9 @@ class Build(
|
||||
self.deallocate_stock(output=output)
|
||||
|
||||
# Remove the build output from the database
|
||||
output.delete()
|
||||
# This is a special case where serialized stock can be deleted,
|
||||
# independedent of the global setting which normally prevents deletion of serialized stock items
|
||||
output.delete(ignore_serial_check=True)
|
||||
|
||||
@transaction.atomic
|
||||
def trim_allocated_stock(self):
|
||||
|
||||
@@ -9,6 +9,7 @@ from rest_framework import status
|
||||
|
||||
from build.models import Build, BuildItem, BuildLine
|
||||
from build.status_codes import BuildStatus
|
||||
from common.settings import set_global_setting
|
||||
from InvenTree.unit_test import InvenTreeAPITestCase
|
||||
from part.models import BomItem, Part
|
||||
from stock.models import StockItem
|
||||
@@ -1548,6 +1549,44 @@ class BuildOutputScrapTest(BuildAPITest):
|
||||
self.assertFalse(completed_output.is_building)
|
||||
|
||||
|
||||
class BuildOutputCancelTest(BuildAPITest):
|
||||
"""Test cancellation of build outputs."""
|
||||
|
||||
def test_cancel_output(self):
|
||||
"""Test cancellation of a build output."""
|
||||
build = Build.objects.get(pk=1)
|
||||
build.part.trackable = True
|
||||
build.part.save()
|
||||
|
||||
N = build.build_outputs.count()
|
||||
|
||||
# Create outputs
|
||||
outputs = build.create_build_output(2, serials=['101', '202'])
|
||||
self.assertEqual(outputs.count(), 2)
|
||||
self.assertEqual(build.build_outputs.count(), N + 2)
|
||||
|
||||
output_ids = list(outputs.values_list('pk', flat=True))
|
||||
|
||||
# Let's cancel one of the outputs
|
||||
set_global_setting('STOCK_ALLOW_DELETE_SERIALIZED', True)
|
||||
url = reverse('api-build-output-delete', kwargs={'pk': build.pk})
|
||||
|
||||
self.post(url, data={'outputs': [{'output': output_ids[0]}]}, expected_code=201)
|
||||
|
||||
# Prevent deletion of serialized stock items, and try again
|
||||
# Note that this should still succeed, independent of the global setting
|
||||
set_global_setting('STOCK_ALLOW_DELETE_SERIALIZED', False)
|
||||
|
||||
self.post(url, data={'outputs': [{'output': output_ids[1]}]}, expected_code=201)
|
||||
|
||||
# The outputs should have been scrapped
|
||||
self.assertEqual(build.build_outputs.count(), N)
|
||||
|
||||
for pk in output_ids:
|
||||
self.assertFalse(StockItem.objects.filter(pk=pk).exists())
|
||||
self.get(reverse('api-stock-detail', kwargs={'pk': pk}), expected_code=404)
|
||||
|
||||
|
||||
class BuildLineTests(BuildAPITest):
|
||||
"""Unit tests for the BuildLine API endpoints."""
|
||||
|
||||
|
||||
@@ -449,9 +449,15 @@ class StockItem(
|
||||
|
||||
order_insertion_by = ['part']
|
||||
|
||||
def delete(self, **kwargs):
|
||||
"""Custom delete method for StockItem model."""
|
||||
if not get_global_setting('STOCK_ALLOW_DELETE_SERIALIZED', cache=False):
|
||||
def delete(self, ignore_serial_check: bool = False, **kwargs):
|
||||
"""Custom delete method for StockItem model.
|
||||
|
||||
Arguments:
|
||||
ignore_serial_check: If True, allow deletion of serialized stock items regardless of global setting
|
||||
"""
|
||||
if not ignore_serial_check and not get_global_setting(
|
||||
'STOCK_ALLOW_DELETE_SERIALIZED', cache=False
|
||||
):
|
||||
if self.serialized:
|
||||
raise ValidationError(_('Serialized stock items cannot be deleted'))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user