feat(minor): add pdf backend hook

added new_pdf_backend hook to run alternate get_pdf function from other apps e.g. print designer.
This commit is contained in:
Maharshi Patel 2025-02-01 19:47:29 +05:30
parent 9a1eab7512
commit dd037f54ea
4 changed files with 67 additions and 16 deletions

View file

@ -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(

View file

@ -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

View file

@ -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("/", "-"))

View file

@ -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")