Refactor printing code into ReportPrintMixin

This commit is contained in:
Oliver Walters 2021-02-12 21:08:33 +11:00
parent a1cf893eb2
commit 9be2989971
2 changed files with 109 additions and 69 deletions

View File

@ -117,6 +117,74 @@ class PartReportMixin:
return valid_parts return valid_parts
class ReportPrintMixin:
"""
Mixin for printing reports
"""
def print(self, request, items_to_print):
"""
Print this report template against a number of pre-validated items.
"""
if len(items_to_print) == 0:
# No valid items provided, return an error message
data = {
'error': _('No valid objects provided to template'),
}
return Response(data, status=400)
outputs = []
# In debug mode, generate single HTML output, rather than PDF
debug_mode = common.models.InvenTreeSetting.get_setting('REPORT_DEBUG_MODE')
# Merge one or more PDF files into a single download
for item in items_to_print:
report = self.get_object()
report.object_to_print = item
if debug_mode:
outputs.append(report.render_to_string(request))
else:
outputs.append(report.render(request))
if debug_mode:
"""
Contatenate all rendered templates into a single HTML string,
and return the string as a HTML response.
"""
html = "\n".join(outputs)
return HttpResponse(html)
else:
"""
Concatenate all rendered pages into a single PDF object,
and return the resulting document!
"""
pages = []
if len(outputs) > 1:
# If more than one output is generated, merge them into a single file
for output in outputs:
doc = output.get_document()
for page in doc.pages:
pages.append(page)
pdf = outputs[0].get_document().copy(pages).write_pdf()
else:
pdf = outputs[0].get_document().write_pdf()
return InvenTree.helpers.DownloadFile(
pdf,
'test_report.pdf',
content_type='application/pdf'
)
class StockItemTestReportList(ReportListView, StockItemReportMixin): class StockItemTestReportList(ReportListView, StockItemReportMixin):
""" """
API endpoint for viewing list of TestReport objects. API endpoint for viewing list of TestReport objects.
@ -191,7 +259,7 @@ class StockItemTestReportDetail(generics.RetrieveUpdateDestroyAPIView):
serializer_class = TestReportSerializer serializer_class = TestReportSerializer
class StockItemTestReportPrint(generics.RetrieveAPIView, StockItemReportMixin): class StockItemTestReportPrint(generics.RetrieveAPIView, StockItemReportMixin, ReportPrintMixin):
""" """
API endpoint for printing a TestReport object API endpoint for printing a TestReport object
""" """
@ -206,63 +274,7 @@ class StockItemTestReportPrint(generics.RetrieveAPIView, StockItemReportMixin):
items = self.get_items() items = self.get_items()
if len(items) == 0: return self.print(request, items)
# No valid items provided, return an error message
data = {
'error': _('Must provide valid StockItem(s)')
}
return Response(data, status=400)
outputs = []
# In debug mode, generate single HTML output, rather than PDF
debug_mode = common.models.InvenTreeSetting.get_setting('REPORT_DEBUG_MODE')
# Merge one or more PDF files into a single download
for item in items:
report = self.get_object()
report.stock_item = item
if debug_mode:
outputs.append(report.render_to_string(request))
else:
outputs.append(report.render(request))
if debug_mode:
"""
Contatenate all rendered templates into a single HTML string,
and return the string as a HTML response.
"""
html = "\n".join(outputs)
return HttpResponse(html)
else:
"""
Concatenate all rendered pages into a single PDF object,
and return the resulting document!
"""
pages = []
if len(outputs) > 1:
# If more than one output is generated, merge them into a single file
for output in outputs:
doc = output.get_document()
for page in doc.pages:
pages.append(page)
pdf = outputs[0].get_document().copy(pages).write_pdf()
else:
pdf = outputs[0].get_document().write_pdf()
return InvenTree.helpers.DownloadFile(
pdf,
'test_report.pdf',
content_type='application/pdf'
)
class BOMReportList(ReportListView, PartReportMixin): class BOMReportList(ReportListView, PartReportMixin):
@ -328,6 +340,33 @@ class BOMReportList(ReportListView, PartReportMixin):
return queryset return queryset
class BOMReportDetail(generics.RetrieveUpdateDestroyAPIView):
"""
API endpoint for a single BillOfMaterialReport object
"""
queryset = BillOfMaterialsReport.objects.all()
serializer_class = BOMReportSerializer
class BOMReportPrint(generics.RetrieveUpdateDestroyAPIView, PartReportMixin, ReportPrintMixin):
"""
API endpoint for printing a BillOfMaterialReport object
"""
queryset = BillOfMaterialsReport.objects.all()
serializer_class = BOMReportSerializer
def get(self, request, *args, **kwargs):
"""
Check if valid part item(s) have been provided
"""
parts = self.get_parts()
return self.print(request, parts)
report_api_urls = [ report_api_urls = [
url(r'bom/', include([ url(r'bom/', include([

View File

@ -183,6 +183,9 @@ class ReportTemplateBase(ReportBase):
""" """
# Pass a single top-level object to the report template
object_to_print = None
def get_context_data(self, request): def get_context_data(self, request):
""" """
Supply context data to the template for rendering Supply context data to the template for rendering
@ -257,9 +260,6 @@ class TestReport(ReportTemplateBase):
def getSubdir(self): def getSubdir(self):
return 'test' return 'test'
# Requires a stock_item object to be given to it before rendering
stock_item = None
filters = models.CharField( filters = models.CharField(
blank=True, blank=True,
max_length=250, max_length=250,
@ -287,11 +287,14 @@ class TestReport(ReportTemplateBase):
return items.exists() return items.exists()
def get_context_data(self, request): def get_context_data(self, request):
stock_item = self.object_to_print
return { return {
'stock_item': self.stock_item, 'stock_item': stock_item,
'part': self.stock_item.part, 'part': stock_item.part,
'results': self.stock_item.testResultMap(), 'results': stock_item.testResultMap(),
'result_list': self.stock_item.testResultList() 'result_list': stock_item.testResultList()
} }
@ -322,8 +325,6 @@ class BillOfMaterialsReport(ReportTemplateBase):
def getSubDir(self): def getSubDir(self):
return 'bom' return 'bom'
# Requires a part object to be given to it before rendering
filters = models.CharField( filters = models.CharField(
blank=True, blank=True,
max_length=250, max_length=250,
@ -336,7 +337,7 @@ class BillOfMaterialsReport(ReportTemplateBase):
def get_context_data(self, request): def get_context_data(self, request):
return { return {
'part': self.part, 'part': self.object_to_print,
'category': self.category, 'category': self.category,
} }