mirror of
https://github.com/inventree/InvenTree.git
synced 2026-07-08 16:11:23 +00:00
Report Generation Updates (#12187)
* Fix for TemplateEditor - Allow dragging of split section * Cleaner report template code * Pass correct error message through * Prevent multiple retries if running in worker thread * Handle report merge error * Add playwright tests for broken report printing * Reduce scope for exception messages * Reduce comment deltas * Adjust unit test * Raise ValidaitonError * Handle message parsing * Additional comment * Fix unit tests
This commit is contained in:
@@ -568,7 +568,7 @@ class InvenTreeParameterMixin(InvenTreePermissionCheckMixin, models.Model):
|
||||
if 'parameters_list' in cache:
|
||||
return cache['parameters_list']
|
||||
|
||||
return self.parameters_list.all()
|
||||
return self.parameters_list.all().prefetch_related('template')
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
"""Handle the deletion of a model instance.
|
||||
|
||||
@@ -25,6 +25,7 @@ from pypdf import PdfWriter
|
||||
import InvenTree.exceptions
|
||||
import InvenTree.helpers
|
||||
import InvenTree.models
|
||||
import InvenTree.ready
|
||||
import report.helpers
|
||||
import report.validators
|
||||
from common.models import DataOutput, RenderChoices, UpdatedUserMixin
|
||||
@@ -578,10 +579,10 @@ class ReportTemplate(TemplateUploadMixin, ReportTemplateBase):
|
||||
raise ValidationError(msg)
|
||||
except TemplateSyntaxError as e:
|
||||
msg = _('Template syntax error')
|
||||
output.mark_failure(msg)
|
||||
output.mark_failure(str(e) or msg)
|
||||
raise ValidationError(f'{msg}: {e!s}')
|
||||
except ValidationError as e:
|
||||
output.mark_failure(str(e))
|
||||
output.mark_failure(','.join(e.messages))
|
||||
raise e
|
||||
except Exception as e:
|
||||
msg = _('Error rendering report')
|
||||
@@ -617,10 +618,10 @@ class ReportTemplate(TemplateUploadMixin, ReportTemplateBase):
|
||||
raise ValidationError(msg)
|
||||
except TemplateSyntaxError as e:
|
||||
msg = _('Template syntax error')
|
||||
output.mark_failure(error=_('Template syntax error'))
|
||||
output.mark_failure(error=str(e) or msg)
|
||||
raise ValidationError(f'{msg}: {e!s}')
|
||||
except ValidationError as e:
|
||||
output.mark_failure(str(e))
|
||||
output.mark_failure(', '.join(e.messages))
|
||||
raise e
|
||||
except Exception as e:
|
||||
msg = _('Error rendering report')
|
||||
@@ -643,6 +644,13 @@ class ReportTemplate(TemplateUploadMixin, ReportTemplateBase):
|
||||
# Something went wrong during the report generation process
|
||||
log_report_error('ReportTemplate.print')
|
||||
|
||||
# If the error occurred in a worker thread, we do not want to raise an error,
|
||||
# as this would cause the worker to retry the task indefinitely
|
||||
if InvenTree.ready.isInWorkerThread():
|
||||
return
|
||||
|
||||
# Raise a ValidationError with the error message
|
||||
# This will be caught by the caller and displayed to the user
|
||||
raise ValidationError({
|
||||
'error': _('Error generating report'),
|
||||
'detail': str(exc),
|
||||
@@ -677,6 +685,12 @@ class ReportTemplate(TemplateUploadMixin, ReportTemplateBase):
|
||||
log_report_error('ReportTemplate.print')
|
||||
msg = _('Error merging report outputs')
|
||||
output.mark_failure(error=msg)
|
||||
|
||||
# If the error occurred in a worker thread, we do not want to raise an error,
|
||||
# as this would cause the worker to retry the task indefinitely
|
||||
if InvenTree.ready.isInWorkerThread():
|
||||
return
|
||||
|
||||
raise ValidationError(msg)
|
||||
|
||||
# Save the generated report to the database
|
||||
|
||||
@@ -461,7 +461,7 @@ def part_image(part: Part, preview: bool = False, thumbnail: bool = False, **kwa
|
||||
TypeError: If provided part is not a Part instance
|
||||
"""
|
||||
if not part or not isinstance(part, Part):
|
||||
raise TypeError(_('part_image tag requires a Part instance'))
|
||||
raise ValidationError(_('part_image tag requires a Part instance'))
|
||||
|
||||
image_filename = InvenTree.helpers.image2name(part.image, preview, thumbnail)
|
||||
|
||||
@@ -487,28 +487,22 @@ def parameter(
|
||||
Returns:
|
||||
A Parameter object, or the provided default value if not found
|
||||
"""
|
||||
if instance is None:
|
||||
raise ValueError('parameter tag requires a valid Model instance')
|
||||
if instance is None or not isinstance(instance, Model):
|
||||
raise ValidationError('parameter tag requires a valid Model instance')
|
||||
|
||||
if not isinstance(instance, Model) or not hasattr(instance, 'parameters'):
|
||||
raise TypeError("parameter tag requires a Model with 'parameters' attribute")
|
||||
if not hasattr(instance, 'parameters'):
|
||||
raise ValidationError(
|
||||
"parameter tag requires a Model with 'parameters' attribute"
|
||||
)
|
||||
|
||||
parameters = instance.parameters_list.all().prefetch_related('template')
|
||||
|
||||
# First try with exact match
|
||||
if (
|
||||
parameter := instance.parameters
|
||||
.prefetch_related('template')
|
||||
.filter(template__name=parameter_name)
|
||||
.first()
|
||||
):
|
||||
if parameter := parameters.filter(template__name=parameter_name).first():
|
||||
return parameter
|
||||
|
||||
# Next, try with case-insensitive match
|
||||
if (
|
||||
parameter := instance.parameters
|
||||
.prefetch_related('template')
|
||||
.filter(template__name__iexact=parameter_name)
|
||||
.first()
|
||||
):
|
||||
if parameter := parameters.filter(template__name__iexact=parameter_name).first():
|
||||
return parameter
|
||||
|
||||
return None
|
||||
|
||||
@@ -15,7 +15,7 @@ from PIL import Image
|
||||
|
||||
from common.models import InvenTreeSetting, Parameter, ParameterTemplate
|
||||
from InvenTree.unit_test import InvenTreeTestCase
|
||||
from part.models import Part # TODO fix import: PartParameter, PartParameterTemplate
|
||||
from part.models import Part
|
||||
from part.test_api import PartImageTestMixin
|
||||
from report.templatetags import barcode as barcode_tags
|
||||
from report.templatetags import report as report_tags
|
||||
@@ -184,7 +184,7 @@ class ReportTagTest(PartImageTestMixin, InvenTreeTestCase):
|
||||
|
||||
def test_part_image(self):
|
||||
"""Unit tests for the 'part_image' tag."""
|
||||
with self.assertRaises(TypeError):
|
||||
with self.assertRaises(ValidationError):
|
||||
report_tags.part_image(None)
|
||||
|
||||
obj = Part.objects.create(name='test', description='test')
|
||||
@@ -502,11 +502,11 @@ class ReportTagTest(PartImageTestMixin, InvenTreeTestCase):
|
||||
self.assertEqual(report_tags.parameter(part, 'Template 1'), parameter)
|
||||
|
||||
# Test with a null part
|
||||
with self.assertRaises(ValueError):
|
||||
with self.assertRaises(ValidationError):
|
||||
report_tags.parameter(None, 'name')
|
||||
|
||||
# Test with an invalid model type
|
||||
with self.assertRaises(TypeError):
|
||||
with self.assertRaises(ValidationError):
|
||||
report_tags.parameter(parameter, 'name')
|
||||
|
||||
def test_render_currency(self):
|
||||
|
||||
Reference in New Issue
Block a user