diff --git a/InvenTree/report/api.py b/InvenTree/report/api.py index 4030874a51..2b8a3cccf1 100644 --- a/InvenTree/report/api.py +++ b/InvenTree/report/api.py @@ -117,6 +117,74 @@ class PartReportMixin: 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): """ API endpoint for viewing list of TestReport objects. @@ -191,7 +259,7 @@ class StockItemTestReportDetail(generics.RetrieveUpdateDestroyAPIView): serializer_class = TestReportSerializer -class StockItemTestReportPrint(generics.RetrieveAPIView, StockItemReportMixin): +class StockItemTestReportPrint(generics.RetrieveAPIView, StockItemReportMixin, ReportPrintMixin): """ API endpoint for printing a TestReport object """ @@ -206,64 +274,8 @@ class StockItemTestReportPrint(generics.RetrieveAPIView, StockItemReportMixin): items = self.get_items() - if len(items) == 0: - # 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' - ) - + return self.print(request, items) + class BOMReportList(ReportListView, PartReportMixin): """ @@ -328,6 +340,33 @@ class BOMReportList(ReportListView, PartReportMixin): 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 = [ url(r'bom/', include([ diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index 42d308dcbc..25b0c09da8 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -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): """ Supply context data to the template for rendering @@ -257,9 +260,6 @@ class TestReport(ReportTemplateBase): def getSubdir(self): return 'test' - # Requires a stock_item object to be given to it before rendering - stock_item = None - filters = models.CharField( blank=True, max_length=250, @@ -287,11 +287,14 @@ class TestReport(ReportTemplateBase): return items.exists() def get_context_data(self, request): + + stock_item = self.object_to_print + return { - 'stock_item': self.stock_item, - 'part': self.stock_item.part, - 'results': self.stock_item.testResultMap(), - 'result_list': self.stock_item.testResultList() + 'stock_item': stock_item, + 'part': stock_item.part, + 'results': stock_item.testResultMap(), + 'result_list': stock_item.testResultList() } @@ -322,8 +325,6 @@ class BillOfMaterialsReport(ReportTemplateBase): def getSubDir(self): return 'bom' - # Requires a part object to be given to it before rendering - filters = models.CharField( blank=True, max_length=250, @@ -336,7 +337,7 @@ class BillOfMaterialsReport(ReportTemplateBase): def get_context_data(self, request): return { - 'part': self.part, + 'part': self.object_to_print, 'category': self.category, }