@@ -683,13 +683,13 @@ def format_value(value, df, doc=None): | |||||
return frappe.utils.formatters.format_value(value, df, doc) | return frappe.utils.formatters.format_value(value, df, doc) | ||||
def get_print_format(doctype, name, print_format=None, style=None, as_pdf=False): | 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.doctype = doctype | ||||
local.form_dict.name = name | local.form_dict.name = name | ||||
local.form_dict.format = print_format | 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: | if as_pdf: | ||||
print_settings = db.get_singles_dict("Print Settings") | print_settings = db.get_singles_dict("Print Settings") | ||||
@@ -34,7 +34,7 @@ class Communication(Document): | |||||
@frappe.whitelist() | @frappe.whitelist() | ||||
def make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent", | def make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent", | ||||
sender=None, recipients=None, communication_medium="Email", send_email=False, | 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): | 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( | 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, | _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, | 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) | date=date) | ||||
def _make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent", | def _make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent", | ||||
sender=None, recipients=None, communication_medium="Email", send_email=False, | 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 | # add to Communication | ||||
sent_via = None | sent_via = None | ||||
@@ -89,7 +89,7 @@ def _make(doctype=None, name=None, content=None, subject=None, sent_or_received | |||||
if send_email: | if send_email: | ||||
d = comm | 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() | @frappe.whitelist() | ||||
def get_customer_supplier(args=None): | def get_customer_supplier(args=None): | ||||
@@ -110,7 +110,7 @@ def get_customer_supplier(args=None): | |||||
} | } | ||||
return {} | 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 | 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: | if send_me_a_copy: | ||||
mail.cc.append(frappe.db.get_value("User", frappe.session.user, "email")) | 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): | for a in json.loads(attachments): | ||||
try: | try: | ||||
@@ -159,6 +141,27 @@ def send_comm_email(d, name, sent_via=None, print_html=None, attachments='[]', s | |||||
send(mail) | 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): | def set_portal_link(sent_via, comm): | ||||
"""set portal link in footer""" | """set portal link in footer""" | ||||
@@ -11,6 +11,7 @@ | |||||
"permlevel": 0 | "permlevel": 0 | ||||
}, | }, | ||||
{ | { | ||||
"default": "1", | |||||
"description": "Send Email Print Attachments as PDF (Recommended)", | "description": "Send Email Print Attachments as PDF (Recommended)", | ||||
"fieldname": "send_print_as_pdf", | "fieldname": "send_print_as_pdf", | ||||
"fieldtype": "Check", | "fieldtype": "Check", | ||||
@@ -32,6 +33,7 @@ | |||||
"permlevel": 0 | "permlevel": 0 | ||||
}, | }, | ||||
{ | { | ||||
"default": "", | |||||
"fieldname": "print_style", | "fieldname": "print_style", | ||||
"fieldtype": "Select", | "fieldtype": "Select", | ||||
"in_list_view": 1, | "in_list_view": 1, | ||||
@@ -48,7 +50,7 @@ | |||||
], | ], | ||||
"icon": "icon-cog", | "icon": "icon-cog", | ||||
"issingle": 1, | "issingle": 1, | ||||
"modified": "2014-07-17 08:08:27.291811", | |||||
"modified": "2014-07-23 04:59:45.626239", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"module": "Core", | "module": "Core", | ||||
"name": "Print Settings", | "name": "Print Settings", | ||||
@@ -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 | execute:frappe.db.sql("""delete from `tabUserRole` where ifnull(parentfield, '')=''""") #2014-06-17 | ||||
frappe.patches.v4_0.remove_user_owner_custom_field | frappe.patches.v4_0.remove_user_owner_custom_field | ||||
execute:frappe.delete_doc("DocType", "Website Template") | 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 | 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 | frappe.patches.v4_1.enable_outgoing_email_settings | ||||
execute:frappe.db.sql("""update `tabSingles` set `value`=`doctype` where `field`='name'""") #2014-07-04 | execute:frappe.db.sql("""update `tabSingles` set `value`=`doctype` where `field`='name'""") #2014-07-04 | ||||
@@ -6,10 +6,21 @@ import frappe | |||||
def execute(): | def execute(): | ||||
frappe.reload_doc("core", "doctype", "print_settings") | 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: | try: | ||||
import pdfkit | import pdfkit | ||||
except ImportError: | except ImportError: | ||||
pass | pass | ||||
else: | 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() |
@@ -189,9 +189,9 @@ th { | |||||
} | } | ||||
@media print { | @media print { | ||||
* { | * { | ||||
color: #000 !important; | |||||
/* color: #000 !important;*/ | |||||
text-shadow: none !important; | text-shadow: none !important; | ||||
background: transparent !important; | |||||
/* background: transparent !important;*/ | |||||
-webkit-box-shadow: none !important; | -webkit-box-shadow: none !important; | ||||
box-shadow: none !important; | box-shadow: none !important; | ||||
} | } | ||||
@@ -211,7 +211,7 @@ th { | |||||
} | } | ||||
pre, | pre, | ||||
blockquote { | blockquote { | ||||
border: 1px solid #999; | |||||
/* border: 1px solid #999;*/ | |||||
page-break-inside: avoid; | page-break-inside: avoid; | ||||
} | } | ||||
@@ -241,24 +241,24 @@ th { | |||||
.navbar { | .navbar { | ||||
display: none; | display: none; | ||||
} | } | ||||
.table td, | |||||
/* .table td, | |||||
.table th { | .table th { | ||||
background-color: #fff !important; | background-color: #fff !important; | ||||
} | } | ||||
.btn > .caret, | |||||
*/ .btn > .caret, | |||||
.dropup > .btn > .caret { | .dropup > .btn > .caret { | ||||
border-top-color: #000 !important; | border-top-color: #000 !important; | ||||
} | } | ||||
.label { | |||||
/* .label { | |||||
border: 1px solid #000; | border: 1px solid #000; | ||||
} | } | ||||
.table { | |||||
*/ .table { | |||||
border-collapse: collapse !important; | border-collapse: collapse !important; | ||||
} | } | ||||
.table-bordered th, | |||||
/*.table-bordered th, | |||||
.table-bordered td { | .table-bordered td { | ||||
border: 1px solid #ddd !important; | border: 1px solid #ddd !important; | ||||
} | |||||
}*/ | |||||
} | } | ||||
@font-face { | @font-face { | ||||
font-family: 'Glyphicons Halflings'; | font-family: 'Glyphicons Halflings'; | ||||
@@ -17,6 +17,7 @@ frappe.ui.form.PrintPreview = Class.extend({ | |||||
<div class="checkbox"><label><input type="checkbox" class="print-letterhead" checked/> Letterhead</label></div></div>\ | <div class="checkbox"><label><input type="checkbox" class="print-letterhead" checked/> Letterhead</label></div></div>\ | ||||
<div class="col-xs-6 text-right" style="padding-top: 7px;">\ | <div class="col-xs-6 text-right" style="padding-top: 7px;">\ | ||||
<a style="margin-right: 7px;" class="btn-print-preview text-muted small">Preview</a>\ | <a style="margin-right: 7px;" class="btn-print-preview text-muted small">Preview</a>\ | ||||
<a style="margin-right: 7px;" class="btn-download-pdf text-muted small">Download PDF</a>\ | |||||
<strong><a style="margin-right: 7px;" class="btn-print-print">Print</a></strong>\ | <strong><a style="margin-right: 7px;" class="btn-print-print">Print</a></strong>\ | ||||
<a class="close">×</a>\ | <a class="close">×</a>\ | ||||
</div>\ | </div>\ | ||||
@@ -42,11 +43,13 @@ frappe.ui.form.PrintPreview = Class.extend({ | |||||
.find(".print-preview-select") | .find(".print-preview-select") | ||||
.on("change", function() { | .on("change", function() { | ||||
if(me.is_old_style()) { | if(me.is_old_style()) { | ||||
me.wrapper.find(".btn-download-pdf").toggle(false); | |||||
me.preview_old_style(); | me.preview_old_style(); | ||||
} else { | } else { | ||||
me.wrapper.find(".btn-download-pdf").toggle(true); | |||||
me.preview(); | me.preview(); | ||||
} | } | ||||
}) | |||||
}); | |||||
this.wrapper.find(".btn-print-print").click(function() { | this.wrapper.find(".btn-print-print").click(function() { | ||||
if(me.is_old_style()) { | if(me.is_old_style()) { | ||||
@@ -63,6 +66,18 @@ frappe.ui.form.PrintPreview = Class.extend({ | |||||
me.new_page_preview(); | 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() { | preview: function() { | ||||
var me = this; | var me = this; | ||||
@@ -102,14 +117,24 @@ frappe.ui.form.PrintPreview = Class.extend({ | |||||
}); | }); | ||||
}, | }, | ||||
preview_old_style: function() { | 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('<div class="alert alert-warning">' | |||||
+__("Warning: This Print Format is in old style and cannot be generated via the API.") | |||||
+'</div>' | |||||
+ html); | |||||
}, | |||||
no_letterhead: !this.with_letterhead(), | |||||
only_body: true, | |||||
no_heading: true | |||||
}); | |||||
}, | |||||
with_old_style: function(opts) { | |||||
var me = this; | var me = this; | ||||
frappe.require("/assets/js/print_format_v3.min.js"); | frappe.require("/assets/js/print_format_v3.min.js"); | ||||
_p.build(me.print_sel.val(), function(html) { | |||||
me.wrapper.find(".print-format").html('<div class="alert alert-warning">' | |||||
+__("Warning: This Print Format is in old style and cannot be generated via the API.") | |||||
+'</div>' | |||||
+ 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() { | print_old_style: function() { | ||||
frappe.require("/assets/js/print_format_v3.min.js"); | frappe.require("/assets/js/print_format_v3.min.js"); | ||||
@@ -124,11 +149,14 @@ frappe.ui.form.PrintPreview = Class.extend({ | |||||
selected_format: function() { | selected_format: function() { | ||||
return this.print_sel.val(); | 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]) { | if(locals["Print Format"] && locals["Print Format"][format]) { | ||||
return locals["Print Format"][format] | return locals["Print Format"][format] | ||||
} else { | } else { | ||||
@@ -264,8 +264,8 @@ frappe.views.CommunicationComposer = Class.extend({ | |||||
if (cur_frm) { | if (cur_frm) { | ||||
$(fields.select_print_format.input) | $(fields.select_print_format.input) | ||||
.empty() | .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 { | } else { | ||||
$(fields.attach_document_print.wrapper).toggle(false); | $(fields.attach_document_print.wrapper).toggle(false); | ||||
} | } | ||||
@@ -324,20 +324,29 @@ frappe.views.CommunicationComposer = Class.extend({ | |||||
}) | }) | ||||
if(form_values.attach_document_print) { | 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 { | } else { | ||||
me.send_email(btn, form_values, selected_attachments); | 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; | var me = this; | ||||
if(!form_values.attach_document_print) { | if(!form_values.attach_document_print) { | ||||
print_html = ""; | |||||
print_html = null; | |||||
print_format = null; | |||||
} | } | ||||
if(form_values.send_email) { | 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_me_a_copy: form_values.send_me_a_copy, | ||||
send_email: form_values.send_email, | send_email: form_values.send_email, | ||||
print_html: print_html, | print_html: print_html, | ||||
print_format: print_format, | |||||
communication_medium: form_values.communication_medium, | communication_medium: form_values.communication_medium, | ||||
sent_or_received: form_values.sent_or_received, | sent_or_received: form_values.sent_or_received, | ||||
attachments: selected_attachments | attachments: selected_attachments | ||||
@@ -86,7 +86,7 @@ $.extend(_p, { | |||||
dialog.onshow = function() { | dialog.onshow = function() { | ||||
var $print = dialog.fields_dict.print_format.$input; | 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()) | if(cur_frm.$print_view_select && cur_frm.$print_view_select.val()) | ||||
$print.val(cur_frm.$print_view_select.val()); | $print.val(cur_frm.$print_view_select.val()); | ||||
@@ -3,12 +3,13 @@ | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import frappe, os, copy, json | |||||
import frappe, os, copy, json, re | |||||
from frappe import _ | from frappe import _ | ||||
from frappe.modules import get_doc_path | from frappe.modules import get_doc_path | ||||
from jinja2 import TemplateNotFound | from jinja2 import TemplateNotFound | ||||
from frappe.utils import cint | from frappe.utils import cint | ||||
from frappe.utils.pdf import get_pdf | |||||
no_cache = 1 | no_cache = 1 | ||||
no_sitemap = 1 | no_sitemap = 1 | ||||
@@ -29,13 +30,6 @@ def get_context(context): | |||||
doc = frappe.get_doc(frappe.form_dict.doctype, frappe.form_dict.name) | 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": """<h1>Error</h1> | |||||
<p>No {ptype} permission</p>""".format(ptype=ptype) | |||||
} | |||||
meta = frappe.get_meta(doc.doctype) | meta = frappe.get_meta(doc.doctype) | ||||
return { | return { | ||||
@@ -59,6 +53,8 @@ def get_html(doc, name=None, print_format=None, meta=None, | |||||
if isinstance(doc, basestring): | if isinstance(doc, basestring): | ||||
doc = frappe.get_doc(json.loads(doc)) | doc = frappe.get_doc(json.loads(doc)) | ||||
validate_print_permission(doc) | |||||
if hasattr(doc, "before_print"): | if hasattr(doc, "before_print"): | ||||
doc.before_print() | doc.before_print() | ||||
@@ -88,6 +84,18 @@ def get_html(doc, name=None, print_format=None, meta=None, | |||||
return html | 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): | def get_letter_head(doc, no_letterhead): | ||||
if no_letterhead: | if no_letterhead: | ||||
return "" | return "" | ||||
@@ -168,12 +176,21 @@ def is_visible(df): | |||||
def get_print_style(style=None): | def get_print_style(style=None): | ||||
if not style: | 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() | css = frappe.get_template("templates/styles/standard.css").render() | ||||
try: | 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: | except TemplateNotFound: | ||||
pass | pass | ||||
@@ -8,7 +8,7 @@ | |||||
{% for section in page %} | {% for section in page %} | ||||
<div class="row"> | <div class="row"> | ||||
{% for column in section %} | {% for column in section %} | ||||
<div class="col-sm-{{ (12 / section|len)|int }}"> | |||||
<div class="col-xs-{{ (12 / section|len)|int }}"> | |||||
{% for df in column %} | {% for df in column %} | ||||
{{ render_field(df, doc) }} | {{ render_field(df, doc) }} | ||||
{% endfor %} | {% endfor %} | ||||
@@ -49,13 +49,13 @@ | |||||
{%- macro render_field_with_label(df, doc) -%} | {%- macro render_field_with_label(df, doc) -%} | ||||
<div class="row"> | <div class="row"> | ||||
<div class="col-sm-5 text-right"> | |||||
<div class="col-xs-5 text-right"> | |||||
{% if df.fieldtype not in ("Image","HTML") and | {% if df.fieldtype not in ("Image","HTML") and | ||||
doc.get(df.fieldname) != None %} | doc.get(df.fieldname) != None %} | ||||
<label>{{ df.label }}</label> | <label>{{ df.label }}</label> | ||||
{% endif %} | {% endif %} | ||||
</div> | </div> | ||||
<div class="col-sm-7 {%- if df.fieldtype | |||||
<div class="col-xs-7 {%- if df.fieldtype | |||||
in ('Int', 'Check', 'Float', 'Currency') %} text-right{% endif %}"> | in ('Int', 'Check', 'Float', 'Currency') %} text-right{% endif %}"> | ||||
{% if doc.get(df.fieldname) != None -%} | {% if doc.get(df.fieldname) != None -%} | ||||
{{ print_value(df, doc) }}{% endif %} | {{ print_value(df, doc) }}{% endif %} | ||||
@@ -75,9 +75,9 @@ | |||||
{%- macro print_value(df, doc, parent_doc=None) -%} | {%- macro print_value(df, doc, parent_doc=None) -%} | ||||
{% if df.fieldtype=="Check" %} | {% if df.fieldtype=="Check" %} | ||||
<i class="{{ 'icon-check' if doc[df.fieldname] else 'icon-check-empty' }}"></i> | |||||
<i class="{{ 'icon-check' if doc[df.fieldname] else 'icon-check-empty' }}"></i> | |||||
{% elif df.fieldtype=="Image" %} | {% elif df.fieldtype=="Image" %} | ||||
<img src="{{ doc[doc.meta.get_field(df.fieldname).options] }}" class="img-responsive"> | |||||
<img src="{{ doc[doc.meta.get_field(df.fieldname).options] }}" class="img-responsive"> | |||||
{% else %} | {% else %} | ||||
{{ doc.get_formatted(df.fieldname, parent_doc or doc) }} | {{ doc.get_formatted(df.fieldname, parent_doc or doc) }} | ||||
{% endif %} | {% endif %} | ||||
@@ -1,3 +1,5 @@ | |||||
@import url(http://fonts.googleapis.com/css?family=Noto+Serif:400,700); | |||||
/* | /* | ||||
common style for whole page | common style for whole page | ||||
This should include: | This should include: | ||||
@@ -12,5 +14,5 @@ | |||||
.print-format h2, | .print-format h2, | ||||
.print-format h3, | .print-format h3, | ||||
.print-format h4 { | .print-format h4 { | ||||
font-family: serif; | |||||
font-family: 'Noto Serif', serif; | |||||
} | } |
@@ -1,3 +1,5 @@ | |||||
@import url(http://fonts.googleapis.com/css?family=Noto+Sans:400,700); | |||||
@media screen { | @media screen { | ||||
.print-format-gutter { | .print-format-gutter { | ||||
background-color: #ddd; | background-color: #ddd; | ||||
@@ -26,8 +28,16 @@ | |||||
} | } | ||||
} | } | ||||
@media print { | |||||
.print-format p { | |||||
margin-left: 1px; | |||||
margin-right: 1px; | |||||
} | |||||
} | |||||
.print-format { | .print-format { | ||||
font-size: 9pt; | font-size: 9pt; | ||||
-webkit-print-color-adjust:exact; | |||||
} | } | ||||
.page-break { | .page-break { | ||||
@@ -49,4 +59,3 @@ | |||||
table.no-border, table.no-border td { | table.no-border, table.no-border td { | ||||
border: 0px; | border: 0px; | ||||
} | } | ||||
@@ -348,9 +348,17 @@ def fmt_money(amount, precision=None, currency=None): | |||||
""" | """ | ||||
Convert to string with commas for thousands, millions etc | 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)) | amount = '%.*f' % (precision, flt(amount)) | ||||
if amount.find('.') == -1: | if amount.find('.') == -1: | ||||
@@ -17,7 +17,7 @@ def get_email(recipients, sender='', msg='', subject='[No Subject]', | |||||
msg = markdown(msg) | msg = markdown(msg) | ||||
emailobj.set_html(msg, text_content, footer=footer, print_html=print_html, formatted=formatted) | 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) | emailobj.add_attachment(**attach) | ||||
return emailobj | return emailobj | ||||
@@ -14,7 +14,7 @@ def format_value(value, df, doc=None): | |||||
currency=get_field_currency(df, doc) if doc else None) | currency=get_field_currency(df, doc) if doc else None) | ||||
elif df.fieldtype == "Float": | elif df.fieldtype == "Float": | ||||
return fmt_money(value) | |||||
return fmt_money(value, precision=get_field_precision(df, doc)) | |||||
elif df.fieldtype == "Percent": | elif df.fieldtype == "Percent": | ||||
return "{}%".format(flt(value, 2)) | return "{}%".format(flt(value, 2)) | ||||
@@ -2,13 +2,28 @@ | |||||
# MIT License. See license.txt | # MIT License. See license.txt | ||||
import pdfkit, os, frappe | import pdfkit, os, frappe | ||||
from frappe.utils import scrub_urls | |||||
def get_pdf(html, options=None): | def get_pdf(html, options=None): | ||||
if not options: | if not options: | ||||
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"): | 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") | fname = os.path.join("/tmp", frappe.generate_hash() + ".pdf") | ||||
pdfkit.from_string(html, fname, options=options or {}) | pdfkit.from_string(html, fname, options=options or {}) | ||||
@@ -49,7 +49,7 @@ def as_csv(): | |||||
def as_raw(): | def as_raw(): | ||||
response = Response() | 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.headers[b"Content-Disposition"] = ("filename=%s" % frappe.response['filename'].replace(' ', '_')).encode("utf-8") | ||||
response.data = frappe.response['filecontent'] | response.data = frappe.response['filecontent'] | ||||
return response | return response | ||||
@@ -3,6 +3,7 @@ | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import frappe | import frappe | ||||
from frappe.utils import cstr | |||||
import mimetypes, json | import mimetypes, json | ||||
from werkzeug.wrappers import Response | from werkzeug.wrappers import Response | ||||
@@ -49,7 +50,7 @@ def render(path, http_status_code=None): | |||||
def render_403(e): | def render_403(e): | ||||
path = "message" | path = "message" | ||||
frappe.local.message = "Did you log out?" | |||||
frappe.local.message = "<p><strong>{error}</strong></p><p>Did you log out?</p>".format(error=cstr(e)) | |||||
frappe.local.message_title = "Not Permitted" | frappe.local.message_title = "Not Permitted" | ||||
return render_page(path), e.http_status_code | return render_page(path), e.http_status_code | ||||