@@ -13,7 +13,7 @@ import os, sys, importlib, inspect, json | |||||
from .exceptions import * | from .exceptions import * | ||||
from .utils.jinja import get_jenv, get_template, render_template | from .utils.jinja import get_jenv, get_template, render_template | ||||
__version__ = '7.1.19' | |||||
__version__ = '7.1.20' | |||||
__title__ = "Frappe Framework" | __title__ = "Frappe Framework" | ||||
local = Local() | local = Local() | ||||
@@ -1152,7 +1152,7 @@ def format(*args, **kwargs): | |||||
import frappe.utils.formatters | import frappe.utils.formatters | ||||
return frappe.utils.formatters.format_value(*args, **kwargs) | 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): | |||||
def get_print(doctype=None, name=None, print_format=None, style=None, html=None, as_pdf=False, doc=None, output = None): | |||||
"""Get Print Format for given document. | """Get Print Format for given document. | ||||
:param doctype: DocType of document. | :param doctype: DocType of document. | ||||
@@ -1173,7 +1173,7 @@ def get_print(doctype=None, name=None, print_format=None, style=None, html=None, | |||||
html = build_page("print") | html = build_page("print") | ||||
if as_pdf: | if as_pdf: | ||||
return get_pdf(html) | |||||
return get_pdf(html, output = output) | |||||
else: | else: | ||||
return html | return html | ||||
@@ -145,15 +145,6 @@ def purge_jobs(site=None, queue=None, event=None): | |||||
count = purge_pending_jobs(event=event, site=site, queue=queue) | count = purge_pending_jobs(event=event, site=site, queue=queue) | ||||
print "Purged {} jobs".format(count) | print "Purged {} jobs".format(count) | ||||
@click.command('dump-queue-status') | |||||
def dump_queue_status(): | |||||
"Dump detailed diagnostic infomation for task queues in JSON format" | |||||
frappe.init('') | |||||
from frappe.utils.doctor import dump_queue_status as _dump_queue_status, inspect_queue | |||||
print json.dumps(_dump_queue_status(), indent=1) | |||||
inspect_queue() | |||||
@click.command('schedule') | @click.command('schedule') | ||||
def start_scheduler(): | def start_scheduler(): | ||||
from frappe.utils.scheduler import start_scheduler | from frappe.utils.scheduler import start_scheduler | ||||
@@ -192,7 +183,6 @@ def ready_for_migration(context, site=None): | |||||
commands = [ | commands = [ | ||||
disable_scheduler, | disable_scheduler, | ||||
doctor, | doctor, | ||||
dump_queue_status, | |||||
enable_scheduler, | enable_scheduler, | ||||
purge_jobs, | purge_jobs, | ||||
ready_for_migration, | ready_for_migration, | ||||
@@ -7,6 +7,11 @@ def get_data(): | |||||
"label": _("Tools"), | "label": _("Tools"), | ||||
"icon": "octicon octicon-briefcase", | "icon": "octicon octicon-briefcase", | ||||
"items": [ | "items": [ | ||||
{ | |||||
"type": "doctype", | |||||
"name": "Newsletter", | |||||
"description": _("Newsletters to contacts, leads."), | |||||
}, | |||||
{ | { | ||||
"type": "doctype", | "type": "doctype", | ||||
"name": "ToDo", | "name": "ToDo", | ||||
@@ -144,11 +144,6 @@ def get_data(): | |||||
"name": "Standard Reply", | "name": "Standard Reply", | ||||
"description": _("Standard replies to common queries.") | "description": _("Standard replies to common queries.") | ||||
}, | }, | ||||
{ | |||||
"type": "doctype", | |||||
"name": "Newsletter", | |||||
"description": _("Newsletters to contacts, leads."), | |||||
}, | |||||
{ | { | ||||
"type": "doctype", | "type": "doctype", | ||||
"name": "Email Group", | "name": "Email Group", | ||||
@@ -231,6 +231,10 @@ def on_doctype_update(): | |||||
frappe.db.add_index("Communication", ["modified"]) | frappe.db.add_index("Communication", ["modified"]) | ||||
def has_permission(doc, ptype, user): | def has_permission(doc, ptype, user): | ||||
if ptype=="read" and doc.reference_doctype and doc.reference_name: | |||||
if frappe.has_permission(doc.reference_doctype, ptype="read", doc=doc.reference_name): | |||||
return True | |||||
if ptype=="read": | |||||
if doc.reference_doctype and doc.reference_name: | |||||
if frappe.has_permission(doc.reference_doctype, ptype="read", doc=doc.reference_name): | |||||
return True | |||||
if doc.timeline_doctype and doc.timeline_name: | |||||
if frappe.has_permission(doc.timeline_doctype, ptype="read", doc=doc.timeline_name): | |||||
return True |
@@ -4,7 +4,7 @@ | |||||
frappe.ui.form.on('Auto Email Report', { | frappe.ui.form.on('Auto Email Report', { | ||||
refresh: function(frm) { | refresh: function(frm) { | ||||
if(frm.doc.report_type !== 'Report Builder') { | if(frm.doc.report_type !== 'Report Builder') { | ||||
if(frm.script_setup_for !== frm.doc.report) { | |||||
if(frm.script_setup_for !== frm.doc.report && !frm.doc.__islocal) { | |||||
frappe.call({ | frappe.call({ | ||||
method:"frappe.desk.query_report.get_script", | method:"frappe.desk.query_report.get_script", | ||||
args: { | args: { | ||||
@@ -6,17 +6,20 @@ import pdfkit, os, frappe | |||||
from frappe.utils import scrub_urls | from frappe.utils import scrub_urls | ||||
from frappe import _ | from frappe import _ | ||||
from bs4 import BeautifulSoup | from bs4 import BeautifulSoup | ||||
from pyPdf import PdfFileWriter, PdfFileReader | |||||
def get_pdf(html, options=None): | |||||
def get_pdf(html, options=None, output = None): | |||||
html = scrub_urls(html) | html = scrub_urls(html) | ||||
html, options = prepare_options(html, options) | html, options = prepare_options(html, options) | ||||
fname = os.path.join("/tmp", "frappe-pdf-{0}.pdf".format(frappe.generate_hash())) | fname = os.path.join("/tmp", "frappe-pdf-{0}.pdf".format(frappe.generate_hash())) | ||||
try: | try: | ||||
pdfkit.from_string(html, fname, options=options or {}) | pdfkit.from_string(html, fname, options=options or {}) | ||||
with open(fname, "rb") as fileobj: | |||||
filedata = fileobj.read() | |||||
if output: | |||||
append_pdf(PdfFileReader(file(fname,"rb")),output) | |||||
else: | |||||
with open(fname, "rb") as fileobj: | |||||
filedata = fileobj.read() | |||||
except IOError, e: | except IOError, e: | ||||
if ("ContentNotFoundError" in e.message | if ("ContentNotFoundError" in e.message | ||||
@@ -37,9 +40,15 @@ def get_pdf(html, options=None): | |||||
finally: | finally: | ||||
cleanup(fname, options) | cleanup(fname, options) | ||||
if output: | |||||
return output | |||||
return filedata | return filedata | ||||
def append_pdf(input,output): | |||||
# Merging multiple pdf files | |||||
[output.addPage(input.getPage(page_num)) for page_num in range(input.numPages)] | |||||
def prepare_options(html, options): | def prepare_options(html, options): | ||||
if not options: | if not options: | ||||
options = {} | options = {} | ||||
@@ -7,6 +7,7 @@ from frappe.modules import get_doc_path | |||||
from jinja2 import TemplateNotFound | from jinja2 import TemplateNotFound | ||||
from frappe.utils import cint, strip_html | from frappe.utils import cint, strip_html | ||||
from frappe.utils.pdf import get_pdf | from frappe.utils.pdf import get_pdf | ||||
from pyPdf import PdfFileWriter, PdfFileReader | |||||
no_cache = 1 | no_cache = 1 | ||||
no_sitemap = 1 | no_sitemap = 1 | ||||
@@ -17,31 +18,28 @@ standard_format = "templates/print_formats/standard.html" | |||||
@frappe.whitelist() | @frappe.whitelist() | ||||
def download_multi_pdf(doctype, name, format=None): | def download_multi_pdf(doctype, name, format=None): | ||||
# name can include names of many docs of the same doctype. | # name can include names of many docs of the same doctype. | ||||
totalhtml = "" | |||||
# Pagebreak to be added between each doc html | |||||
pagebreak = """<p style="page-break-after:always;"></p>""" | |||||
options = {} | |||||
import json | import json | ||||
result = json.loads(name) | result = json.loads(name) | ||||
# Get html of each doc and combine including page breaks | |||||
# Concatenating pdf files | |||||
output = PdfFileWriter() | |||||
for i, ss in enumerate(result): | for i, ss in enumerate(result): | ||||
html = frappe.get_print(doctype, ss, format) | |||||
if i == len(result)-1: | |||||
totalhtml = totalhtml + html | |||||
else: | |||||
totalhtml = totalhtml + html + pagebreak | |||||
output = frappe.get_print(doctype, ss, format, as_pdf = True, output = output) | |||||
frappe.local.response.filename = "{doctype}.pdf".format(doctype=doctype.replace(" ", "-").replace("/", "-")) | frappe.local.response.filename = "{doctype}.pdf".format(doctype=doctype.replace(" ", "-").replace("/", "-")) | ||||
frappe.local.response.filecontent = read_multi_pdf(output) | |||||
frappe.local.response.type = "download" | |||||
# Title of pdf | |||||
options.update({ | |||||
'title': doctype, | |||||
}) | |||||
def read_multi_pdf(output): | |||||
# Get the content of the merged pdf files | |||||
fname = os.path.join("/tmp", "frappe-pdf-{0}.pdf".format(frappe.generate_hash())) | |||||
output.write(open(fname,"wb")) | |||||
frappe.local.response.filecontent = get_pdf(totalhtml, options) | |||||
frappe.local.response.type = "download" | |||||
with open(fname, "rb") as fileobj: | |||||
filedata = fileobj.read() | |||||
return filedata | |||||
@frappe.whitelist() | @frappe.whitelist() | ||||
def download_pdf(doctype, name, format=None, doc=None): | def download_pdf(doctype, name, format=None, doc=None): | ||||
@@ -39,3 +39,4 @@ psutil | |||||
unittest-xml-reporting | unittest-xml-reporting | ||||
xlwt | xlwt | ||||
oauthlib | oauthlib | ||||
pypdf |