From dd037f54ea523ca3e66cc6949e7edd17f21731ec Mon Sep 17 00:00:00 2001 From: Maharshi Patel Date: Sat, 1 Feb 2025 19:47:29 +0530 Subject: [PATCH] feat(minor): add pdf backend hook added new_pdf_backend hook to run alternate get_pdf function from other apps e.g. print designer. --- frappe/__init__.py | 22 ++++++++++++++++++++- frappe/utils/pdf.py | 38 ++++++++++++++++++++++++------------ frappe/utils/print_format.py | 18 +++++++++++++++-- frappe/www/printview.py | 5 ++++- 4 files changed, 67 insertions(+), 16 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index a035d02543..47efba5357 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -2107,6 +2107,7 @@ def get_print( password=None, pdf_options=None, letterhead=None, + force_new_backend=False, ): """Get Print Format for given document. @@ -2119,6 +2120,10 @@ def get_print( from frappe.utils.pdf import get_pdf from frappe.website.serve import get_response_without_exception_handling + new_pdf_backend = force_new_backend or frappe.get_cached_value( + "Print Format", print_format, "new_pdf_backend" + ) + local.form_dict.new_pdf_backend = new_pdf_backend original_form_dict = copy.deepcopy(local.form_dict) try: local.form_dict.doctype = doctype @@ -2138,7 +2143,22 @@ def get_print( finally: local.form_dict = original_form_dict - return get_pdf(html, options=pdf_options, output=output) if as_pdf else html + if not as_pdf: + return html + + if new_pdf_backend: + hook_func = frappe.get_hooks("new_pdf_backend") + if hook_func: + return frappe.call( + hook_func[-1], + print_format=print_format, + html=html, + options=pdf_options, + output=output, + new_pdf_backend=new_pdf_backend, + ) + + return get_pdf(html, options=pdf_options, output=output, new_pdf_backend=new_pdf_backend) def attach_print( diff --git a/frappe/utils/pdf.py b/frappe/utils/pdf.py index 4f9b874278..604b222649 100644 --- a/frappe/utils/pdf.py +++ b/frappe/utils/pdf.py @@ -33,9 +33,12 @@ PDF_CONTENT_ERRORS = [ ] -def pdf_header_html(soup, head, content, styles, html_id, css): +def pdf_header_html(soup, head, content, styles, html_id, css, new_pdf_backend=False): + path = "templates/print_formats/pdf_header_footer.html" + if new_pdf_backend: + path = "templates/print_formats/pdf_header_footer_chrome.html" return frappe.render_template( - "templates/print_formats/pdf_header_footer.html", + path, { "head": head, "content": content, @@ -44,6 +47,7 @@ def pdf_header_html(soup, head, content, styles, html_id, css): "css": css, "lang": frappe.local.lang, "layout_direction": "rtl" if is_rtl() else "ltr", + "new_pdf_backend": new_pdf_backend, }, ) @@ -75,13 +79,21 @@ def _guess_template_error_line_number(template) -> int | None: return frame.lineno -def pdf_footer_html(soup, head, content, styles, html_id, css): - return pdf_header_html(soup=soup, head=head, content=content, styles=styles, html_id=html_id, css=css) +def pdf_footer_html(soup, head, content, styles, html_id, css, new_pdf_backend=False): + return pdf_header_html( + soup=soup, + head=head, + content=content, + styles=styles, + html_id=html_id, + css=css, + new_pdf_backend=new_pdf_backend, + ) -def get_pdf(html, options=None, output: PdfWriter | None = None): +def get_pdf(html, options=None, output: PdfWriter | None = None, new_pdf_backend=False): html = scrub_urls(html) - html, options = prepare_options(html, options) + html, options = prepare_options(html, options, new_pdf_backend) options.update({"disable-javascript": "", "disable-local-file-access": ""}) @@ -139,7 +151,7 @@ def get_file_data_from_writer(writer_obj): return stream.read() -def prepare_options(html, options): +def prepare_options(html, options, new_pdf_backend): if not options: options = {} @@ -161,7 +173,7 @@ def prepare_options(html, options): if not options.get("margin-left"): options["margin-left"] = "15mm" - html, html_options = read_options_from_html(html) + html, html_options = read_options_from_html(html, new_pdf_backend) options.update(html_options or {}) # cookies @@ -203,11 +215,11 @@ def get_cookie_options(): return options -def read_options_from_html(html): +def read_options_from_html(html, new_pdf_backend): options = {} soup = BeautifulSoup(html, "html5lib") - options.update(prepare_header_footer(soup)) + options.update(prepare_header_footer(soup, new_pdf_backend)) toggle_visible_pdf(soup) @@ -294,7 +306,7 @@ def _get_base64_image(src): frappe.logger("pdf").error("Failed to convert inline images to base64", exc_info=True) -def prepare_header_footer(soup: BeautifulSoup): +def prepare_header_footer(soup: BeautifulSoup, new_pdf_backend): options = {} head = soup.find("head").contents @@ -316,13 +328,15 @@ def prepare_header_footer(soup: BeautifulSoup): toggle_visible_pdf(content) id_map = {"header-html": "pdf_header_html", "footer-html": "pdf_footer_html"} hook_func = frappe.get_hooks(id_map.get(html_id)) - html = frappe.get_attr(hook_func[-1])( + html = frappe.call( + hook_func[-1], soup=soup, head=head, content=content, styles=styles, html_id=html_id, css=css, + new_pdf_backend=new_pdf_backend, ) # create temp file diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index 5b651054e4..3c6def09e1 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -218,14 +218,28 @@ from frappe.deprecation_dumpster import read_multi_pdf @frappe.whitelist(allow_guest=True) def download_pdf( - doctype: str, name: str, format=None, doc=None, no_letterhead=0, language=None, letterhead=None + doctype: str, + name: str, + format=None, + doc=None, + no_letterhead=0, + language=None, + letterhead=None, + force_new_backend=False, ): doc = doc or frappe.get_doc(doctype, name) validate_print_permission(doc) with print_language(language): pdf_file = frappe.get_print( - doctype, name, format, doc=doc, as_pdf=True, letterhead=letterhead, no_letterhead=no_letterhead + doctype, + name, + format, + doc=doc, + as_pdf=True, + letterhead=letterhead, + no_letterhead=no_letterhead, + force_new_backend=force_new_backend, ) frappe.local.response.filename = "{name}.pdf".format(name=name.replace(" ", "-").replace("/", "-")) diff --git a/frappe/www/printview.py b/frappe/www/printview.py index e2c1c77872..01fecddc2c 100644 --- a/frappe/www/printview.py +++ b/frappe/www/printview.py @@ -75,7 +75,6 @@ def get_context(context) -> PrintContext: make_access_log( doctype=frappe.form_dict.doctype, document=frappe.form_dict.name, file_type="PDF", method="Print" ) - body = get_rendered_template( doc, print_format=print_format, @@ -84,6 +83,7 @@ def get_context(context) -> PrintContext: no_letterhead=frappe.form_dict.no_letterhead, letterhead=letterhead, settings=settings, + new_pdf_backend=frappe.form_dict.new_pdf_backend, ) print_style = get_print_style(frappe.form_dict.style, print_format) @@ -100,6 +100,7 @@ def get_context(context) -> PrintContext: "print_format": getattr(print_format, "name", None), "letterhead": letterhead, "no_letterhead": frappe.form_dict.no_letterhead, + "new_pdf_backend": frappe.form_dict.new_pdf_backend, } @@ -126,6 +127,7 @@ def get_rendered_template( letterhead: str | None = None, trigger_print: bool = False, settings: dict | None = None, + new_pdf_backend: bool = False, ) -> str: print_settings = frappe.get_single("Print Settings").as_dict() print_settings.update(settings or {}) @@ -244,6 +246,7 @@ def get_rendered_template( "letter_head": letter_head.content, "footer": letter_head.footer, "print_settings": print_settings, + "new_pdf_backend": new_pdf_backend, } ) hook_func = frappe.get_hooks("pdf_body_html")