diff --git a/src/backend/InvenTree/report/api.py b/src/backend/InvenTree/report/api.py index a62d2b7a98..deb5acc5e0 100644 --- a/src/backend/InvenTree/report/api.py +++ b/src/backend/InvenTree/report/api.py @@ -226,6 +226,7 @@ class LabelPrint(GenericAPIView): output.pk, user.pk if user else None, plugin.slug, + retry=False, options=(plugin_serializer.data if plugin_serializer else {}), ) diff --git a/src/backend/InvenTree/report/tasks.py b/src/backend/InvenTree/report/tasks.py index 3a148bf0f8..8a1a6b4ae6 100644 --- a/src/backend/InvenTree/report/tasks.py +++ b/src/backend/InvenTree/report/tasks.py @@ -118,13 +118,6 @@ def print_labels( ) return - if output.errors: - # A failed job may have printed some labels already - do not print them again - logger.info( - 'DataOutput %s has already failed - skipping print_labels task', output_id - ) - return - # Fetch user information user = None diff --git a/src/backend/InvenTree/report/tests.py b/src/backend/InvenTree/report/tests.py index d455052c09..cf3504bea9 100644 --- a/src/backend/InvenTree/report/tests.py +++ b/src/backend/InvenTree/report/tests.py @@ -549,6 +549,38 @@ class LabelTest(InvenTreeAPITestCase): output = plugin.get_generated_file(**kwargs) self.assertEqual(output.name, expected) + def test_print_task_single_shot(self): + """API print jobs acknowledge failures without retrying the whole label batch.""" + from django_q.models import OrmQ + + OrmQ.objects.all().delete() + + template = LabelTemplate.objects.filter(enabled=True, model_type='part').first() + part = Part.objects.first() + + with patch('InvenTree.status.is_worker_running', return_value=True): + response = self.post( + reverse('api-label-print'), + data={'template': template.pk, 'items': [part.pk]}, + expected_code=201, + ) + + task = OrmQ.objects.get() + self.assertEqual(task.func(), 'report.tasks.print_labels') + self.assertTrue(task.q_options().get('ack_failure')) + self.assertEqual( + task.args(), + ( + template.pk, + [part.pk], + response.data['pk'], + self.user.pk, + 'inventreelabel', + ), + ) + self.assertEqual(task.kwargs(), {'options': {}}) + self.assertFalse(response.data['complete']) + def test_print_failure(self): """Printing failures retain their details and propagate to the caller.""" template = LabelTemplate.objects.filter(enabled=True, model_type='part').first() @@ -604,35 +636,6 @@ class LabelTest(InvenTreeAPITestCase): 'Error printing labels: printer unavailable', ) - if worker: - original = ( - report_models.DataOutput.objects - .filter(pk=output.pk) - .values() - .get() - ) - with patch.object( - registry, 'get_plugin', return_value=plugin - ) as get_plugin: - print_labels( - template.pk, - [part.pk for part in parts], - output.pk, - self.user.pk, - plugin.slug, - options={}, - ) - - get_plugin.assert_not_called() - plugin.print_labels.assert_called_once() - self.assertEqual( - report_models.DataOutput.objects - .filter(pk=output.pk) - .values() - .get(), - original, - ) - def test_print_unavailable_plugin(self): """An unavailable worker plugin records a failure instead of hanging.""" template = LabelTemplate.objects.filter(enabled=True, model_type='part').first() @@ -660,23 +663,6 @@ class LabelTest(InvenTreeAPITestCase): {'error': "Label printing plugin 'unavailable-label' not found"}, ) - original = report_models.DataOutput.objects.filter(pk=output.pk).values().get() - plugin = Mock(spec=['slug', 'print_labels'], slug=output.plugin) - with ( - patch.object(registry, 'get_plugin', return_value=plugin) as get_plugin, - patch.object(LabelTemplate, 'print') as print_template, - ): - print_labels( - template.pk, [], output.pk, self.user.pk, output.plugin, options={} - ) - - get_plugin.assert_not_called() - print_template.assert_not_called() - self.assertEqual( - report_models.DataOutput.objects.filter(pk=output.pk).values().get(), - original, - ) - def test_print_task_duplicate(self): """Duplicate tasks skip completed or deleted outputs before plugin lookup.""" template = LabelTemplate.objects.filter(enabled=True, model_type='part').first()