From 64c18a31870665b1d4e04b1b257a8bfe3db2f675 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Tue, 26 Oct 2021 16:06:32 +0530 Subject: [PATCH 1/2] feat: allow more print page size options --- frappe/__init__.py | 11 +- .../print_settings/print_settings.json | 16 ++- .../doctype/print_settings/print_settings.py | 15 ++- .../public/js/frappe/list/bulk_operations.js | 115 +++++++++++------- frappe/public/js/frappe/model/meta.js | 9 ++ frappe/utils/pdf.py | 19 ++- frappe/utils/print_format.py | 9 +- 7 files changed, 138 insertions(+), 56 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index c8245b0bf0..3d3acd99e2 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -1512,8 +1512,8 @@ def format(*args, **kwargs): import frappe.utils.formatters return frappe.utils.formatters.format_value(*args, **kwargs) -def get_print(doctype=None, name=None, print_format=None, style=None, - html=None, as_pdf=False, doc=None, output=None, no_letterhead=0, password=None): +def get_print(doctype=None, name=None, print_format=None, style=None, html=None, + as_pdf=False, doc=None, output=None, no_letterhead=0, password=None, pdf_options=None): """Get Print Format for given document. :param doctype: DocType of document. @@ -1532,15 +1532,16 @@ def get_print(doctype=None, name=None, print_format=None, style=None, local.form_dict.doc = doc local.form_dict.no_letterhead = no_letterhead - options = None + if not pdf_options: + pdf_options = {} if password: - options = {'password': password} + pdf_options['password'] = password if not html: html = get_response_content("printview") if as_pdf: - return get_pdf(html, output = output, options = options) + return get_pdf(html, options=pdf_options, output=output) else: return html diff --git a/frappe/printing/doctype/print_settings/print_settings.json b/frappe/printing/doctype/print_settings/print_settings.json index babbae248d..f45de7637d 100644 --- a/frappe/printing/doctype/print_settings/print_settings.json +++ b/frappe/printing/doctype/print_settings/print_settings.json @@ -10,6 +10,8 @@ "repeat_header_footer", "column_break_4", "pdf_page_size", + "pdf_page_height", + "pdf_page_width", "view_link_in_email", "with_letterhead", "allow_print_for_draft", @@ -56,7 +58,7 @@ "fieldname": "pdf_page_size", "fieldtype": "Select", "label": "PDF Page Size", - "options": "A4\nLetter" + "options": "A0\nA1\nA2\nA3\nA4\nA5\nA6\nA7\nA8\nA9\nB0\nB1\nB2\nB3\nB4\nB5\nB6\nB7\nB8\nB9\nB10\nC5E\nComm10E\nDLE\nExecutive\nFolio\nLedger\nLegal\nLetter\nTabloid\nCustom" }, { "fieldname": "view_link_in_email", @@ -156,6 +158,18 @@ "fieldname": "font_size", "fieldtype": "Float", "label": "Font Size" + }, + { + "depends_on": "eval:doc.pdf_page_size == \"Custom\"", + "fieldname": "pdf_page_height", + "fieldtype": "Float", + "label": "PDF Page Height (in mm)" + }, + { + "depends_on": "eval:doc.pdf_page_size == \"Custom\"", + "fieldname": "pdf_page_width", + "fieldtype": "Float", + "label": "PDF Page Width (in mm)" } ], "icon": "fa fa-cog", diff --git a/frappe/printing/doctype/print_settings/print_settings.py b/frappe/printing/doctype/print_settings/print_settings.py index ff00317cf8..5eb8d8b215 100644 --- a/frappe/printing/doctype/print_settings/print_settings.py +++ b/frappe/printing/doctype/print_settings/print_settings.py @@ -8,14 +8,23 @@ from frappe.utils import cint from frappe.model.document import Document + class PrintSettings(Document): + def validate(self): + if self.pdf_page_size == "Custom" and ( + not self.pdf_page_height or not self.pdf_page_width + ): + frappe.throw(_("Page height and width cannot be zero")) + def on_update(self): frappe.clear_cache() + @frappe.whitelist() def is_print_server_enabled(): - if not hasattr(frappe.local, 'enable_print_server'): - frappe.local.enable_print_server = cint(frappe.db.get_single_value('Print Settings', - 'enable_print_server')) + if not hasattr(frappe.local, "enable_print_server"): + frappe.local.enable_print_server = cint( + frappe.db.get_single_value("Print Settings", "enable_print_server") + ) return frappe.local.enable_print_server diff --git a/frappe/public/js/frappe/list/bulk_operations.js b/frappe/public/js/frappe/list/bulk_operations.js index ee6e6d753c..94ec9d4e67 100644 --- a/frappe/public/js/frappe/list/bulk_operations.js +++ b/frappe/public/js/frappe/list/bulk_operations.js @@ -24,51 +24,84 @@ export default class BulkOperations { return; } - if (valid_docs.length > 0) { - const dialog = new frappe.ui.Dialog({ - title: __('Print Documents'), - fields: [ - { - 'fieldtype': 'Select', - 'label': __('Letter Head'), - 'fieldname': 'letter_sel', - 'default': __('No Letterhead'), - options: this.get_letterhead_options() - }, - { - 'fieldtype': 'Select', - 'label': __('Print Format'), - 'fieldname': 'print_sel', - options: frappe.meta.get_print_formats(this.doctype) - } - ] - }); + if (valid_docs.length === 0) { + frappe.msgprint(__('Select atleast 1 record for printing')); + return; + } + + const dialog = new frappe.ui.Dialog({ + title: __('Print Documents'), + fields: [{ + fieldtype: 'Select', + label: __('Letter Head'), + fieldname: 'letter_sel', + default: __('No Letterhead'), + options: this.get_letterhead_options() + }, + { + fieldtype: 'Select', + label: __('Print Format'), + fieldname: 'print_sel', + options: frappe.meta.get_print_formats(this.doctype) + }, + { + fieldtype: 'Select', + label: __('Page Size'), + fieldname: 'page_size', + options: frappe.meta.get_print_sizes(), + default: print_settings.pdf_page_size + }, + { + fieldtype: 'Float', + label: __('Page Height (in mm)'), + fieldname: 'page_height', + depends_on: 'eval:doc.page_size == "Custom"', + default: print_settings.pdf_page_height + }, + { + fieldtype: 'Float', + label: __('Page Width (in mm)'), + fieldname: 'page_width', + depends_on: 'eval:doc.page_size == "Custom"', + default: print_settings.pdf_page_width + }] + }); - dialog.set_primary_action(__('Print'), args => { - if (!args) return; - const default_print_format = frappe.get_meta(this.doctype).default_print_format; - const with_letterhead = args.letter_sel == __("No Letterhead") ? 0 : 1; - const print_format = args.print_sel ? args.print_sel : default_print_format; - const json_string = JSON.stringify(valid_docs); - const letterhead = args.letter_sel; - const w = window.open('/api/method/frappe.utils.print_format.download_multi_pdf?' + - 'doctype=' + encodeURIComponent(this.doctype) + - '&name=' + encodeURIComponent(json_string) + - '&format=' + encodeURIComponent(print_format) + - '&no_letterhead=' + (with_letterhead ? '0' : '1') + - '&letterhead=' + encodeURIComponent(letterhead) - ); + dialog.set_primary_action(__('Print'), args => { + if (!args) return; + const default_print_format = frappe.get_meta(this.doctype).default_print_format; + const with_letterhead = args.letter_sel == __("No Letterhead") ? 0 : 1; + const print_format = args.print_sel ? args.print_sel : default_print_format; + const json_string = JSON.stringify(valid_docs); + const letterhead = args.letter_sel; - if (!w) { - frappe.msgprint(__('Please enable pop-ups')); - return; + let pdf_options; + if (args.page_size === "Custom") { + if (args.page_height === 0 || args.page_width === 0) { + frappe.throw(__('Page height and width cannot be zero')); } - }); + pdf_options = JSON.stringify({ "page-height": args.page_height, "page-width": args.page_width }); + } else { + pdf_options = JSON.stringify({ "page-size": args.page_size }); + } - dialog.show(); - } else { - frappe.msgprint(__('Select atleast 1 record for printing')); - } + const w = window.open( + '/api/method/frappe.utils.print_format.download_multi_pdf?' + + 'doctype=' + encodeURIComponent(this.doctype) + + '&name=' + encodeURIComponent(json_string) + + '&format=' + encodeURIComponent(print_format) + + '&no_letterhead=' + (with_letterhead ? '0' : '1') + + '&letterhead=' + encodeURIComponent(letterhead) + + '&options=' + encodeURIComponent(pdf_options) + ); + + if (!w) { + frappe.msgprint(__('Please enable pop-ups')); + return; + } + }); + + dialog.show(); } get_letterhead_options () { diff --git a/frappe/public/js/frappe/model/meta.js b/frappe/public/js/frappe/model/meta.js index 6ee9084adc..3c9ddc4d96 100644 --- a/frappe/public/js/frappe/model/meta.js +++ b/frappe/public/js/frappe/model/meta.js @@ -192,6 +192,15 @@ $.extend(frappe.meta, { } }, + get_print_sizes: function() { + return [ + "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", + "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "B10", + "C5E", "Comm10E", "DLE", "Executive", "Folio", "Ledger", "Legal", + "Letter", "Tabloid", "Custom" + ]; + }, + get_print_formats: function(doctype) { var print_format_list = ["Standard"]; var default_print_format = locals.DocType[doctype].default_print_format; diff --git a/frappe/utils/pdf.py b/frappe/utils/pdf.py index 90bb4f63de..9a7c0889b5 100644 --- a/frappe/utils/pdf.py +++ b/frappe/utils/pdf.py @@ -95,7 +95,7 @@ def prepare_options(html, options): 'quiet': None, # 'no-outline': None, 'encoding': "UTF-8", - #'load-error-handling': 'ignore' + # 'load-error-handling': 'ignore' }) if not options.get("margin-right"): @@ -111,8 +111,21 @@ def prepare_options(html, options): options.update(get_cookie_options()) # page size - if not options.get("page-size"): - options['page-size'] = frappe.db.get_single_value("Print Settings", "pdf_page_size") or "A4" + pdf_page_size = ( + options.get("page-size") + or frappe.db.get_single_value("Print Settings", "pdf_page_size") + or "A4" + ) + + if pdf_page_size == "Custom": + options["page-height"] = options.get("page-height") or frappe.db.get_single_value( + "Print Settings", "pdf_page_height" + ) + options["page-width"] = options.get("page-width") or frappe.db.get_single_value( + "Print Settings", "pdf_page_width" + ) + else: + options["page-size"] = pdf_page_size return html, options diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index 6dfa3a350b..06f15ced27 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -11,7 +11,7 @@ base_template_path = "www/printview.html" standard_format = "templates/print_formats/standard.html" @frappe.whitelist() -def download_multi_pdf(doctype, name, format=None, no_letterhead=0): +def download_multi_pdf(doctype, name, format=None, no_letterhead=False, options=None): """ Concatenate multiple docs as PDF . @@ -54,18 +54,21 @@ def download_multi_pdf(doctype, name, format=None, no_letterhead=0): import json output = PdfFileWriter() + if isinstance(options, str): + options = json.loads(options) + if not isinstance(doctype, dict): result = json.loads(name) # Concatenating pdf files for i, ss in enumerate(result): - output = frappe.get_print(doctype, ss, format, as_pdf = True, output = output, no_letterhead=no_letterhead) + output = frappe.get_print(doctype, ss, format, as_pdf=True, output=output, no_letterhead=no_letterhead, pdf_options=options) frappe.local.response.filename = "{doctype}.pdf".format(doctype=doctype.replace(" ", "-").replace("/", "-")) else: for doctype_name in doctype: for doc_name in doctype[doctype_name]: try: - output = frappe.get_print(doctype_name, doc_name, format, as_pdf = True, output = output, no_letterhead=no_letterhead) + output = frappe.get_print(doctype_name, doc_name, format, as_pdf=True, output=output, no_letterhead=no_letterhead, pdf_options=options) except Exception: frappe.log_error("Permission Error on doc {} of doctype {}".format(doc_name, doctype_name)) frappe.local.response.filename = "{}.pdf".format(name) From c5464e2c5a0f72039a6ace5df17e383e8e7b5c10 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Thu, 4 Nov 2021 14:50:37 +0530 Subject: [PATCH 2/2] fix: requested changes --- frappe/__init__.py | 3 +-- frappe/printing/doctype/print_settings/print_settings.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index cf5642b452..63ff2f83f7 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -1542,8 +1542,7 @@ def get_print(doctype=None, name=None, print_format=None, style=None, html=None, local.form_dict.doc = doc local.form_dict.no_letterhead = no_letterhead - if not pdf_options: - pdf_options = {} + pdf_options = pdf_options or {} if password: pdf_options['password'] = password diff --git a/frappe/printing/doctype/print_settings/print_settings.py b/frappe/printing/doctype/print_settings/print_settings.py index 5eb8d8b215..3253cea2dc 100644 --- a/frappe/printing/doctype/print_settings/print_settings.py +++ b/frappe/printing/doctype/print_settings/print_settings.py @@ -11,8 +11,8 @@ from frappe.model.document import Document class PrintSettings(Document): def validate(self): - if self.pdf_page_size == "Custom" and ( - not self.pdf_page_height or not self.pdf_page_width + if self.pdf_page_size == "Custom" and not ( + self.pdf_page_height and self.pdf_page_width ): frappe.throw(_("Page height and width cannot be zero"))