From 7087be6559edfd6048ab63de819eb684f4a3779a Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 23 Jul 2014 20:12:27 +0530 Subject: [PATCH] Fixes to print --- frappe/__init__.py | 6 +-- .../doctype/communication/communication.py | 53 ++++++++++--------- .../print_settings/print_settings.json | 4 +- frappe/patches.txt | 2 +- frappe/patches/v4_1/enable_print_as_pdf.py | 15 +++++- frappe/public/css/bootstrap.css | 18 +++---- frappe/public/js/frappe/form/print.js | 50 +++++++++++++---- .../public/js/frappe/views/communication.js | 24 ++++++--- frappe/public/js/legacy/print_format.js | 2 +- frappe/templates/pages/print.py | 37 +++++++++---- frappe/templates/print_formats/standard.html | 2 +- .../print_formats/standard_macros.html | 8 +-- frappe/templates/styles/classic.css | 4 +- frappe/templates/styles/standard.css | 11 +++- frappe/utils/__init__.py | 12 ++++- frappe/utils/email_lib/email_body.py | 2 +- frappe/utils/formatters.py | 2 +- frappe/utils/pdf.py | 17 +++++- frappe/utils/response.py | 2 +- frappe/website/render.py | 3 +- 20 files changed, 190 insertions(+), 84 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index a6f98ce184..b0b0631cd4 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -683,13 +683,13 @@ def format_value(value, df, doc=None): return frappe.utils.formatters.format_value(value, df, doc) def get_print_format(doctype, name, print_format=None, style=None, as_pdf=False): - from frappe.website.render import render_page + from frappe.website.render import build_page local.form_dict.doctype = doctype local.form_dict.name = name local.form_dict.format = print_format - local.form_dict.name = name + local.form_dict.style = style - html = render_page("print") + html = build_page("print") if as_pdf: print_settings = db.get_singles_dict("Print Settings") diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index 072e9faef9..47546c221b 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -34,7 +34,7 @@ class Communication(Document): @frappe.whitelist() def make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent", sender=None, recipients=None, communication_medium="Email", send_email=False, - print_html=None, attachments='[]', send_me_a_copy=False, set_lead=True, date=None): + print_html=None, print_format=None, attachments='[]', send_me_a_copy=False, set_lead=True, date=None): if doctype and name and not frappe.has_permission(doctype, "email", name): raise frappe.PermissionError("You are not allowed to send emails related to: {doctype} {name}".format( @@ -42,12 +42,12 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received = _make(doctype=doctype, name=name, content=content, subject=subject, sent_or_received=sent_or_received, sender=sender, recipients=recipients, communication_medium=communication_medium, send_email=send_email, - print_html=print_html, attachments=attachments, send_me_a_copy=send_me_a_copy, set_lead=set_lead, + print_html=print_html, print_format=print_format, attachments=attachments, send_me_a_copy=send_me_a_copy, set_lead=set_lead, date=date) def _make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent", sender=None, recipients=None, communication_medium="Email", send_email=False, - print_html=None, attachments='[]', send_me_a_copy=False, set_lead=True, date=None): + print_html=None, print_format=None, attachments='[]', send_me_a_copy=False, set_lead=True, date=None): # add to Communication sent_via = None @@ -89,7 +89,7 @@ def _make(doctype=None, name=None, content=None, subject=None, sent_or_received if send_email: d = comm - send_comm_email(d, name, sent_via, print_html, attachments, send_me_a_copy) + send_comm_email(d, name, sent_via, print_html, print_format, attachments, send_me_a_copy) @frappe.whitelist() def get_customer_supplier(args=None): @@ -110,7 +110,7 @@ def get_customer_supplier(args=None): } return {} -def send_comm_email(d, name, sent_via=None, print_html=None, attachments='[]', send_me_a_copy=False): +def send_comm_email(d, name, sent_via=None, print_html=None, print_format=None, attachments='[]', send_me_a_copy=False): footer = None @@ -130,26 +130,8 @@ def send_comm_email(d, name, sent_via=None, print_html=None, attachments='[]', s if send_me_a_copy: mail.cc.append(frappe.db.get_value("User", frappe.session.user, "email")) - if print_html: - print_html = scrub_urls(print_html) - - print_settings = frappe.get_singles_dict("Print Settings") - send_print_as_pdf = cint(print_settings.send_print_as_pdf) - - if send_print_as_pdf: - try: - options = { - 'page-size': print_settings.pdf_page_size or 'A4' - } - mail.add_pdf_attachment(name.replace(' ','').replace('/','-') + '.pdf', print_html, - options=options) - except Exception: - frappe.msgprint(_("Error generating PDF, attachment sent as HTML")) - send_print_as_pdf = 0 - - if not send_print_as_pdf: - mail.add_attachment(name.replace(' ','').replace('/','-') + '.html', - print_html, 'text/html') + if print_html or print_format: + attach_print(mail, sent_via, print_html, print_format) for a in json.loads(attachments): try: @@ -159,6 +141,27 @@ def send_comm_email(d, name, sent_via=None, print_html=None, attachments='[]', s send(mail) +def attach_print(mail, sent_via, print_html, print_format): + name = sent_via.name + if not print_html and print_format: + print_html = frappe.get_print_format(sent_via.doctype, sent_via.name, print_format) + + print_settings = frappe.db.get_singles_dict("Print Settings") + send_print_as_pdf = cint(print_settings.send_print_as_pdf) + + if send_print_as_pdf: + try: + mail.add_pdf_attachment(name.replace(' ','').replace('/','-') + '.pdf', print_html) + except Exception: + frappe.msgprint(_("Error generating PDF, attachment sent as HTML")) + frappe.errprint(frappe.get_traceback()) + send_print_as_pdf = 0 + + if not send_print_as_pdf: + print_html = scrub_urls(print_html) + mail.add_attachment(name.replace(' ','').replace('/','-') + '.html', + print_html, 'text/html') + def set_portal_link(sent_via, comm): """set portal link in footer""" diff --git a/frappe/core/doctype/print_settings/print_settings.json b/frappe/core/doctype/print_settings/print_settings.json index f1e365cbee..576836cece 100644 --- a/frappe/core/doctype/print_settings/print_settings.json +++ b/frappe/core/doctype/print_settings/print_settings.json @@ -11,6 +11,7 @@ "permlevel": 0 }, { + "default": "1", "description": "Send Email Print Attachments as PDF (Recommended)", "fieldname": "send_print_as_pdf", "fieldtype": "Check", @@ -32,6 +33,7 @@ "permlevel": 0 }, { + "default": "", "fieldname": "print_style", "fieldtype": "Select", "in_list_view": 1, @@ -48,7 +50,7 @@ ], "icon": "icon-cog", "issingle": 1, - "modified": "2014-07-17 08:08:27.291811", + "modified": "2014-07-23 04:59:45.626239", "modified_by": "Administrator", "module": "Core", "name": "Print Settings", diff --git a/frappe/patches.txt b/frappe/patches.txt index abe17e867d..427676c64a 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -41,7 +41,7 @@ execute:frappe.reset_perms("User") #2014-06-13 execute:frappe.db.sql("""delete from `tabUserRole` where ifnull(parentfield, '')=''""") #2014-06-17 frappe.patches.v4_0.remove_user_owner_custom_field execute:frappe.delete_doc("DocType", "Website Template") -execute:frappe.reload_doc('website', 'doctype', 'website_route') #20114-06-17 +execute:frappe.reload_doc('website', 'doctype', 'website_route') #2014-06-17 execute:frappe.db.sql("""update `tabProperty Setter` set property_type='Text' where property in ('options', 'default')""") #2014-06-20 frappe.patches.v4_1.enable_outgoing_email_settings execute:frappe.db.sql("""update `tabSingles` set `value`=`doctype` where `field`='name'""") #2014-07-04 diff --git a/frappe/patches/v4_1/enable_print_as_pdf.py b/frappe/patches/v4_1/enable_print_as_pdf.py index 94cb96ff8b..877a2b61f7 100644 --- a/frappe/patches/v4_1/enable_print_as_pdf.py +++ b/frappe/patches/v4_1/enable_print_as_pdf.py @@ -6,10 +6,21 @@ import frappe def execute(): frappe.reload_doc("core", "doctype", "print_settings") - frappe.db.set_value("Print Settings", "Print Settings", "print_style", "Modern") + print_settings = frappe.get_doc("Print Settings") + print_settings.print_style = "Modern" + try: import pdfkit except ImportError: pass else: - frappe.db.set_value("Print Settings", "Print Settings", "send_print_as_pdf", 1) + # if someone has already configured in Outgoing Email Settings + outgoing_email_settings = frappe.db.get_singles_dict("Outgoing Email Settings") + if "send_print_as_pdf" in outgoing_email_settings: + print_settings.send_print_as_pdf = outgoing_email_settings.send_print_as_pdf + print_settings.pdf_page_size = outgoing_email_settings.pdf_page_size + + else: + print_settings.send_print_as_pdf = 1 + + print_settings.save() diff --git a/frappe/public/css/bootstrap.css b/frappe/public/css/bootstrap.css index 60babbec0b..c6e36fc3e6 100644 --- a/frappe/public/css/bootstrap.css +++ b/frappe/public/css/bootstrap.css @@ -189,9 +189,9 @@ th { } @media print { * { - color: #000 !important; +/* color: #000 !important;*/ text-shadow: none !important; - background: transparent !important; +/* background: transparent !important;*/ -webkit-box-shadow: none !important; box-shadow: none !important; } @@ -211,7 +211,7 @@ th { } pre, blockquote { - border: 1px solid #999; +/* border: 1px solid #999;*/ page-break-inside: avoid; } @@ -241,24 +241,24 @@ th { .navbar { display: none; } - .table td, +/* .table td, .table th { background-color: #fff !important; } - .btn > .caret, +*/ .btn > .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } - .label { +/* .label { border: 1px solid #000; } - .table { +*/ .table { border-collapse: collapse !important; } - .table-bordered th, + /*.table-bordered th, .table-bordered td { border: 1px solid #ddd !important; - } + }*/ } @font-face { font-family: 'Glyphicons Halflings'; diff --git a/frappe/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index f23e072592..be569b3981 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -17,6 +17,7 @@ frappe.ui.form.PrintPreview = Class.extend({
\
\ Preview\ + Download PDF\ Print\ ×\
\ @@ -42,11 +43,13 @@ frappe.ui.form.PrintPreview = Class.extend({ .find(".print-preview-select") .on("change", function() { if(me.is_old_style()) { + me.wrapper.find(".btn-download-pdf").toggle(false); me.preview_old_style(); } else { + me.wrapper.find(".btn-download-pdf").toggle(true); me.preview(); } - }) + }); this.wrapper.find(".btn-print-print").click(function() { if(me.is_old_style()) { @@ -63,6 +66,18 @@ frappe.ui.form.PrintPreview = Class.extend({ me.new_page_preview(); } }); + + this.wrapper.find(".btn-download-pdf").click(function() { + if(!me.is_old_style()) { + var w = window.open("/api/method/frappe.templates.pages.print.download_pdf?" + +"doctype="+encodeURIComponent(me.frm.doc.doctype) + +"&name="+encodeURIComponent(me.frm.doc.name) + +"&format="+me.selected_format()); + if(!w) { + msgprint(__("Please enable pop-ups")); return; + } + } + }); }, preview: function() { var me = this; @@ -102,14 +117,24 @@ frappe.ui.form.PrintPreview = Class.extend({ }); }, preview_old_style: function() { + var me = this; + this.with_old_style({ + format: me.print_sel.val(), + callback: function(html) { + me.wrapper.find(".print-format").html('
' + +__("Warning: This Print Format is in old style and cannot be generated via the API.") + +'
' + + html); + }, + no_letterhead: !this.with_letterhead(), + only_body: true, + no_heading: true + }); + }, + with_old_style: function(opts) { var me = this; frappe.require("/assets/js/print_format_v3.min.js"); - _p.build(me.print_sel.val(), function(html) { - me.wrapper.find(".print-format").html('
' - +__("Warning: This Print Format is in old style and cannot be generated via the API.") - +'
' - + html); - }, !this.with_letterhead(), true, true); + _p.build(opts.format, opts.callback, opts.no_letterhead, opts.only_body, opts.no_heading); }, print_old_style: function() { frappe.require("/assets/js/print_format_v3.min.js"); @@ -124,11 +149,14 @@ frappe.ui.form.PrintPreview = Class.extend({ selected_format: function() { return this.print_sel.val(); }, - is_old_style: function() { - return this.get_print_format().print_format_type==="Client" + is_old_style: function(format) { + return this.get_print_format(format).print_format_type==="Client"; }, - get_print_format: function() { - var format = this.selected_format(); + get_print_format: function(format) { + if (!format) { + format = this.selected_format(); + } + if(locals["Print Format"] && locals["Print Format"][format]) { return locals["Print Format"][format] } else { diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js index 53677ce6a3..f71575c8d3 100644 --- a/frappe/public/js/frappe/views/communication.js +++ b/frappe/public/js/frappe/views/communication.js @@ -264,8 +264,8 @@ frappe.views.CommunicationComposer = Class.extend({ if (cur_frm) { $(fields.select_print_format.input) .empty() - .add_options(cur_frm.print_formats) - .val(cur_frm.print_formats[0]); + .add_options(cur_frm.print_preview.print_formats) + .val(cur_frm.print_preview.print_formats[0]); } else { $(fields.attach_document_print.wrapper).toggle(false); } @@ -324,20 +324,29 @@ frappe.views.CommunicationComposer = Class.extend({ }) if(form_values.attach_document_print) { - _p.build(form_values.select_print_format || "", function(print_format_html) { - me.send_email(btn, form_values, selected_attachments, print_format_html); - }); + if (cur_frm.print_preview.is_old_style(form_values.select_print_format || "")) { + cur_frm.print_preview.with_old_style({ + format: form_values.select_print_format, + callback: function(print_html) { + me.send_email(btn, form_values, selected_attachments, print_html); + } + }); + } else { + me.send_email(btn, form_values, selected_attachments, null, form_values.select_print_format || ""); + } + } else { me.send_email(btn, form_values, selected_attachments); } }); }, - send_email: function(btn, form_values, selected_attachments, print_html) { + send_email: function(btn, form_values, selected_attachments, print_html, print_format) { var me = this; if(!form_values.attach_document_print) { - print_html = ""; + print_html = null; + print_format = null; } if(form_values.send_email) { @@ -362,6 +371,7 @@ frappe.views.CommunicationComposer = Class.extend({ send_me_a_copy: form_values.send_me_a_copy, send_email: form_values.send_email, print_html: print_html, + print_format: print_format, communication_medium: form_values.communication_medium, sent_or_received: form_values.sent_or_received, attachments: selected_attachments diff --git a/frappe/public/js/legacy/print_format.js b/frappe/public/js/legacy/print_format.js index 06729f775a..591cc417e3 100644 --- a/frappe/public/js/legacy/print_format.js +++ b/frappe/public/js/legacy/print_format.js @@ -86,7 +86,7 @@ $.extend(_p, { dialog.onshow = function() { var $print = dialog.fields_dict.print_format.$input; - $print.empty().add_options(cur_frm.print_formats); + $print.empty().add_options(cur_frm.print_preview.print_formats); if(cur_frm.$print_view_select && cur_frm.$print_view_select.val()) $print.val(cur_frm.$print_view_select.val()); diff --git a/frappe/templates/pages/print.py b/frappe/templates/pages/print.py index ff36e1c33b..2638211d8d 100644 --- a/frappe/templates/pages/print.py +++ b/frappe/templates/pages/print.py @@ -3,12 +3,13 @@ from __future__ import unicode_literals -import frappe, os, copy, json +import frappe, os, copy, json, re from frappe import _ from frappe.modules import get_doc_path from jinja2 import TemplateNotFound from frappe.utils import cint +from frappe.utils.pdf import get_pdf no_cache = 1 no_sitemap = 1 @@ -29,13 +30,6 @@ def get_context(context): doc = frappe.get_doc(frappe.form_dict.doctype, frappe.form_dict.name) - for ptype in ("read", "print"): - if not frappe.has_permission(doc.doctype, ptype, doc): - return { - "body": """

Error

-

No {ptype} permission

""".format(ptype=ptype) - } - meta = frappe.get_meta(doc.doctype) return { @@ -59,6 +53,8 @@ def get_html(doc, name=None, print_format=None, meta=None, if isinstance(doc, basestring): doc = frappe.get_doc(json.loads(doc)) + validate_print_permission(doc) + if hasattr(doc, "before_print"): doc.before_print() @@ -88,6 +84,18 @@ def get_html(doc, name=None, print_format=None, meta=None, return html +@frappe.whitelist() +def download_pdf(doctype, name, format=None): + html = frappe.get_print_format(doctype, name, format) + frappe.local.response.filename = "{name}.pdf".format(name=name.replace(" ", "-").replace("/", "-")) + frappe.local.response.filecontent = get_pdf(html) + frappe.local.response.type = "download" + +def validate_print_permission(doc): + for ptype in ("read", "print"): + if not frappe.has_permission(doc.doctype, ptype, doc): + raise frappe.PermissionError(_("No {0} permission").format(ptype)) + def get_letter_head(doc, no_letterhead): if no_letterhead: return "" @@ -168,12 +176,21 @@ def is_visible(df): def get_print_style(style=None): if not style: - style = frappe.db.get_default("print_style") or "Standard" + style = frappe.db.get_single_value("Print Settings", "print_style") or "Standard" css = frappe.get_template("templates/styles/standard.css").render() try: - css += frappe.get_template("templates/styles/" + style.lower() + ".css").render() + additional_css = frappe.get_template("templates/styles/" + style.lower() + ".css").render() + + # move @import to top + for at_import in list(set(re.findall("(@import url\([^\)]+\)[;]?)", additional_css))): + additional_css = additional_css.replace(at_import, "") + + # prepend css with at_import + css = at_import + css + + css += additional_css except TemplateNotFound: pass diff --git a/frappe/templates/print_formats/standard.html b/frappe/templates/print_formats/standard.html index 209ae9dad6..c3d9add59c 100644 --- a/frappe/templates/print_formats/standard.html +++ b/frappe/templates/print_formats/standard.html @@ -8,7 +8,7 @@ {% for section in page %}
{% for column in section %} -
+
{% for df in column %} {{ render_field(df, doc) }} {% endfor %} diff --git a/frappe/templates/print_formats/standard_macros.html b/frappe/templates/print_formats/standard_macros.html index 82754e15a6..b738ab07e4 100644 --- a/frappe/templates/print_formats/standard_macros.html +++ b/frappe/templates/print_formats/standard_macros.html @@ -49,13 +49,13 @@ {%- macro render_field_with_label(df, doc) -%}
-
+
{% if df.fieldtype not in ("Image","HTML") and doc.get(df.fieldname) != None %} {% endif %}
-
{% if doc.get(df.fieldname) != None -%} {{ print_value(df, doc) }}{% endif %} @@ -75,9 +75,9 @@ {%- macro print_value(df, doc, parent_doc=None) -%} {% if df.fieldtype=="Check" %} - + {% elif df.fieldtype=="Image" %} - + {% else %} {{ doc.get_formatted(df.fieldname, parent_doc or doc) }} {% endif %} diff --git a/frappe/templates/styles/classic.css b/frappe/templates/styles/classic.css index b35e1044fd..14d3920a2e 100644 --- a/frappe/templates/styles/classic.css +++ b/frappe/templates/styles/classic.css @@ -1,3 +1,5 @@ +@import url(http://fonts.googleapis.com/css?family=Noto+Serif:400,700); + /* common style for whole page This should include: @@ -12,5 +14,5 @@ .print-format h2, .print-format h3, .print-format h4 { - font-family: serif; + font-family: 'Noto Serif', serif; } diff --git a/frappe/templates/styles/standard.css b/frappe/templates/styles/standard.css index 5666c76643..312da52da3 100644 --- a/frappe/templates/styles/standard.css +++ b/frappe/templates/styles/standard.css @@ -1,3 +1,5 @@ +@import url(http://fonts.googleapis.com/css?family=Noto+Sans:400,700); + @media screen { .print-format-gutter { background-color: #ddd; @@ -26,8 +28,16 @@ } } +@media print { + .print-format p { + margin-left: 1px; + margin-right: 1px; + } +} + .print-format { font-size: 9pt; + -webkit-print-color-adjust:exact; } .page-break { @@ -49,4 +59,3 @@ table.no-border, table.no-border td { border: 0px; } - diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py index 21c6f2c965..7501b8a906 100644 --- a/frappe/utils/__init__.py +++ b/frappe/utils/__init__.py @@ -348,9 +348,17 @@ def fmt_money(amount, precision=None, currency=None): """ Convert to string with commas for thousands, millions etc """ - number_format = frappe.db.get_default("number_format") or "#,###.##" - decimal_str, comma_str, precision = get_number_format_info(number_format) + number_format = None + if currency: + number_format = frappe.db.get_value("Currency", currency, "number_format") + + if not number_format: + number_format = frappe.db.get_default("number_format") or "#,###.##" + + decimal_str, comma_str, number_format_precision = get_number_format_info(number_format) + if not precision: + precision = number_format_precision amount = '%.*f' % (precision, flt(amount)) if amount.find('.') == -1: diff --git a/frappe/utils/email_lib/email_body.py b/frappe/utils/email_lib/email_body.py index 6d9132cf3e..c01dff8950 100644 --- a/frappe/utils/email_lib/email_body.py +++ b/frappe/utils/email_lib/email_body.py @@ -17,7 +17,7 @@ def get_email(recipients, sender='', msg='', subject='[No Subject]', msg = markdown(msg) emailobj.set_html(msg, text_content, footer=footer, print_html=print_html, formatted=formatted) - for attach in attachments: + for attach in (attachments or []): emailobj.add_attachment(**attach) return emailobj diff --git a/frappe/utils/formatters.py b/frappe/utils/formatters.py index 1a2a9ceee2..d8e283c843 100644 --- a/frappe/utils/formatters.py +++ b/frappe/utils/formatters.py @@ -14,7 +14,7 @@ def format_value(value, df, doc=None): currency=get_field_currency(df, doc) if doc else None) elif df.fieldtype == "Float": - return fmt_money(value) + return fmt_money(value, precision=get_field_precision(df, doc)) elif df.fieldtype == "Percent": return "{}%".format(flt(value, 2)) diff --git a/frappe/utils/pdf.py b/frappe/utils/pdf.py index 610dc8a832..0837e816f5 100644 --- a/frappe/utils/pdf.py +++ b/frappe/utils/pdf.py @@ -2,13 +2,28 @@ # MIT License. See license.txt import pdfkit, os, frappe +from frappe.utils import scrub_urls def get_pdf(html, options=None): if not options: options = {} + + options.update({ + "print-media-type": None, + "background": None, + "images": None, + 'margin-top': '15mm', + 'margin-right': '15mm', + 'margin-bottom': '15mm', + 'margin-left': '15mm', + 'encoding': "UTF-8", + 'no-outline': None + }) + if not options.get("page-size"): - options['page-size'] = frappe.df.get_single_value("Print Settings", "pdf_page_size") or "A4" + options['page-size'] = frappe.db.get_single_value("Print Settings", "pdf_page_size") or "A4" + html = scrub_urls(html) fname = os.path.join("/tmp", frappe.generate_hash() + ".pdf") pdfkit.from_string(html, fname, options=options or {}) diff --git a/frappe/utils/response.py b/frappe/utils/response.py index 69056fbb43..9c8db420f8 100644 --- a/frappe/utils/response.py +++ b/frappe/utils/response.py @@ -49,7 +49,7 @@ def as_csv(): def as_raw(): response = Response() - response.headers[b"Content-Type"] = mimetypes.guess_type(frappe.response['filename'])[0] or b"application/unknown" + response.headers[b"Content-Type"] = frappe.response.get("content_type") or mimetypes.guess_type(frappe.response['filename'])[0] or b"application/unknown" response.headers[b"Content-Disposition"] = ("filename=%s" % frappe.response['filename'].replace(' ', '_')).encode("utf-8") response.data = frappe.response['filecontent'] return response diff --git a/frappe/website/render.py b/frappe/website/render.py index de9e07e899..2ecc5ca1c8 100644 --- a/frappe/website/render.py +++ b/frappe/website/render.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import frappe +from frappe.utils import cstr import mimetypes, json from werkzeug.wrappers import Response @@ -49,7 +50,7 @@ def render(path, http_status_code=None): def render_403(e): path = "message" - frappe.local.message = "Did you log out?" + frappe.local.message = "

{error}

Did you log out?

".format(error=cstr(e)) frappe.local.message_title = "Not Permitted" return render_page(path), e.http_status_code