Merge branch 'develop' of https://github.com/frappe/frappe into develop

This commit is contained in:
alsum 2018-08-12 11:22:16 +02:00
commit cb4e4505ad
23 changed files with 3454 additions and 2883 deletions

View file

@ -679,7 +679,7 @@ def clear_document_cache(doctype, name):
def get_cached_value(doctype, name, fieldname, as_dict=False):
doc = get_cached_doc(doctype, name)
if isinstance(fieldname, text_type):
if isinstance(fieldname, string_types):
if as_dict:
throw('Cannot make dict for single fieldname')
return doc.get(fieldname)

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,7 @@ import json
from email.utils import formataddr
from frappe.core.utils import get_parent_doc
from frappe.utils import (get_url, get_formatted_email, cint,
validate_email_add, split_emails, time_diff_in_seconds, parse_addr)
validate_email_add, split_emails, time_diff_in_seconds, parse_addr, get_datetime)
from frappe.utils.file_manager import get_file
from frappe.email.queue import check_email_limit
from frappe.utils.scheduler import log
@ -524,3 +524,27 @@ def update_mins_to_first_communication(parent, communication):
if parent.meta.has_field('first_responded_on'):
parent.db_set('first_responded_on', first_responded_on)
parent.db_set('mins_to_first_response', round(time_diff_in_seconds(first_responded_on, parent.creation) / 60), 2)
@frappe.whitelist(allow_guest=True)
def mark_email_as_seen(name=None):
try:
if name and frappe.db.exists("Communication", name) and not frappe.db.get_value("Communication", name, "read_by_recipient"):
frappe.db.set_value("Communication", name, "read_by_recipient", 1)
frappe.db.set_value("Communication", name, "delivery_status", "Read")
frappe.db.set_value("Communication", name, "read_by_recipient_on", get_datetime())
frappe.db.commit()
except Exception:
frappe.log_error(frappe.get_traceback())
finally:
# Return image as response under all circumstances
from PIL import Image
import io
im = Image.new('RGBA', (1, 1))
im.putdata([(255,255,255,0)])
buffered_obj = io.BytesIO()
im.save(buffered_obj, format="PNG")
frappe.response["type"] = 'binary'
frappe.response["filename"] = "imaginary_pixel.png"
frappe.response["filecontent"] = buffered_obj.getvalue()

View file

@ -363,7 +363,7 @@ class DocType(Document):
with open(fname, 'r') as f:
code = f.read()
with open(fname, 'w') as f:
f.write(code.replace(frappe.scurb(old).replace(' ', ''), frappe.scrub(new).replace(' ', '')))
f.write(code.replace(frappe.scrub(old).replace(' ', ''), frappe.scrub(new).replace(' ', '')))
def before_reload(self):
"""Preserve naming series changes in Property Setter."""

View file

@ -143,7 +143,7 @@ def get_communication_data(doctype, name, start=0, limit=20, after=None, fields=
content, sender, sender_full_name, creation, subject, delivery_status, _liked_by,
timeline_doctype, timeline_name,
reference_doctype, reference_name,
link_doctype, link_name,
link_doctype, link_name, read_by_recipient,
rating, "Communication" as doctype'''
conditions = '''communication_type in ("Communication", "Comment", "Feedback")
@ -228,4 +228,4 @@ def get_view_logs(doctype, docname):
if view_logs:
logs = view_logs
return logs
return logs

View file

@ -6,7 +6,7 @@
data-docname="{%= reference_name %}"
data-link-doctype="{{ link_doctype }}"
data-link-name="{{ link_name }}"
title="{%= by %} / {%= dateutil.str_to_user(creation) %}">
title="{%= by %} / {%= frappe.datetime.str_to_user(creation) %}">
{{ avatar }}
<span class="small">
{% if (feed_type==="Login") { %}

File diff suppressed because it is too large Load diff

View file

@ -52,7 +52,7 @@ class EmailAccount(Document):
"name": ("!=", self.name)
})
if duplicate_email_account:
frappe.throw(_("Email id must be unique, Email Account is already exist \
frappe.throw(_("Email ID must be unique, Email Account already exists \
for {0}".format(frappe.bold(self.email_id))))
if frappe.local.flags.in_patch or frappe.local.flags.in_test:

View file

@ -269,7 +269,10 @@ def get_unsubscribe_message(unsubscribe_message, expose_recipients):
target="_blank">{0}</a>'''.format(_('Unsubscribe'))
unsubscribe_html = _("{0} to stop receiving emails of this type").format(unsubscribe_link)
html = """<div class="email-unsubscribe">
html = """<div class="email-pixel">
<!--email open check-->
</div>
<div class="email-unsubscribe">
<!--cc message-->
<div>
{0}
@ -480,6 +483,15 @@ def prepare_message(email, recipient, recipients_list):
if not message:
return ""
# Parse "Email Account" from "Email Sender"
email_account = email.sender.rsplit('<',1)[0]
if frappe.conf.use_ssl and frappe.db.get_value("Email Account", {"name": email_account}, "track_email_status"):
# Using SSL => Publically available domain => Email Read Reciept Possible
message = message.replace("<!--email open check-->", quopri.encodestring('<img src="https://{}/api/method/frappe.core.doctype.communication.email.mark_email_as_seen?name={}"/>'.format(frappe.local.site, email.communication).encode()).decode())
else:
# No SSL => No Email Read Reciept
message = message.replace("<!--email open check-->", quopri.encodestring("".encode()).decode())
if email.add_unsubscribe_link and email.reference_doctype: # is missing the check for unsubscribe message but will not add as there will be no unsubscribe url
unsubscribe_url = get_unsubcribed_url(email.reference_doctype, email.reference_name, recipient,
email.unsubscribe_method, email.unsubscribe_params)

View file

@ -282,6 +282,8 @@ class FrappeClient(object):
return params
def post_process(self, response):
response.raise_for_status()
try:
rjson = response.json()
except ValueError:

View file

@ -1,18 +1,41 @@
// Copyright (c) 2017, Frappe Technologies and contributors
// Copyright (c) 2018, Frappe Technologies and contributors
// For license information, please see license.txt
frappe.ui.form.on("Print Settings", "print_style", function (frm) {
frappe.db.get_value('Print Style', frm.doc.print_style, 'preview').then((r) => {
if(r.message.preview) {
frm.get_field("print_style_preview").$wrapper.html(
`<img src="${r.message.preview}" class="img-responsive">`);
} else {
frm.get_field("print_style_preview").$wrapper.html(
`<p style="margin: 60px 0px" class="text-center text-muted">${__("No Preview")}</p>`);
frappe.ui.form.on('Print Settings', {
print_style: function(frm) {
frappe.db.get_value('Print Style', frm.doc.print_style, 'preview').then((r) => {
if(r.message.preview) {
frm.get_field("print_style_preview").$wrapper.html(
`<img src="${r.message.preview}" class="img-responsive">`);
} else {
frm.get_field("print_style_preview").$wrapper.html(
`<p style="margin: 60px 0px" class="text-center text-muted">${__("No Preview")}</p>`);
}
});
},
onload: function(frm) {
frm.script_manager.trigger("print_style");
},
server_ip: function(frm) {
frm.trigger("connect_print_server");
},
port:function(frm) {
frm.trigger("connect_print_server");
},
connect_print_server:function(frm) {
if(frm.doc.server_ip && frm.doc.port){
frappe.call({
"doc": frm.doc,
"method": "get_printers",
"args": {
ip: frm.doc.server_ip,
port: frm.doc.port
},
callback: function(data) {
frm.set_df_property('printer_name', 'options', [""].concat(data.message));
},
error: (data) => frm.set_value("enable_print_server", 0)
});
}
});
});
frappe.ui.form.on("Print Settings", "onload", function (frm) {
frm.script_manager.trigger("print_style");
}
});

View file

@ -13,6 +13,7 @@
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -38,10 +39,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -69,10 +72,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -100,10 +105,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -129,10 +136,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -160,10 +169,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -190,10 +201,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -221,10 +234,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -253,10 +268,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -285,10 +302,44 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "enable_print_server",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Enable Print Server",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -314,10 +365,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -345,10 +398,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -375,10 +430,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -406,10 +463,174 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.enable_print_server == 1",
"fieldname": "server_printer",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Print Server",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "localhost",
"fieldname": "server_ip",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Server IP",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "printer_name",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Printer Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_17",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "631",
"fieldname": "port",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Port",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -435,10 +656,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -466,10 +689,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -495,10 +720,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -524,10 +751,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -556,10 +785,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -586,6 +817,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
@ -600,7 +832,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-08-18 01:04:26.692081",
"modified": "2018-06-29 01:34:57.508272",
"modified_by": "Administrator",
"module": "Printing",
"name": "Print Settings",
@ -609,7 +841,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
@ -635,5 +866,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
"track_seen": 0,
"track_views": 0
}

View file

@ -1,11 +1,33 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies and contributors
# Copyright (c) 2018, Frappe Technologies and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
class PrintSettings(Document):
def on_update(self):
frappe.clear_cache()
@frappe.whitelist()
def get_printers(self,ip="localhost",port=631):
printer_list = []
try:
import cups
except ModuleNotFoundError:
frappe.throw("You need to install pycups to use this feature!")
return
try:
cups.setServer(self.server_ip)
cups.setPort(self.port)
conn = cups.Connection()
printers = conn.getPrinters()
printer_list = printers.keys()
except RuntimeError:
frappe.throw(_("Failed to connect to server"))
except ValidationError:
frappe.throw(_("Failed to connect to server"))
return printer_list

View file

@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals
import unittest
class TestPrintSettings(unittest.TestCase):
pass

View file

@ -2,7 +2,7 @@
{% if(field.print_hide) { %}style="background-color: #F7FAFC; color: #8D99A6;"
title="{{ __("Hidden") }}"{% } %}
data-fieldname="{%= field.fieldname %}"
data-label="{{ field.label }}"
data-label="{{ __(field.label) }}"
{% if field.align %}data-align="{{ field.align }}"{% endif %}
data-fieldtype="{%= field.fieldtype %}"
@ -25,7 +25,7 @@
data-custom-html-id={{ field.custom_html_id }}{% endif %}>
{{ field.options || me.get_no_content() }}</div>
{% } else { %}
<span class="field-label">{{ field.label }}</span>
<span class="field-label">{{ __(field.label) }}</span>
{% if(field.fieldtype==="Table") { %}
<span> ({%= __("Table") %})</span>
<a class="pull-right select-columns btn btn-default btn-xs">

View file

@ -19,6 +19,6 @@
</div>
<div class="print-format-builder-add-section text-muted text-center">
<span class="octicon octicon-plus"></span>
<a class="grey">Add a new section</a>
<a class="grey">{%= __("Add a new section") %}</a>
</div>
</div>

View file

@ -10,7 +10,7 @@
<span class="btn btn-xs field-label
{%= (f.fieldtype==="Custom HTML") ? "btn-info" : "btn-default" %}"
style="cursor: grab; display: inline-block">
{%= f.label %}
{%= __(f.label) %}
</span>
</div>
{% } %}

View file

@ -63,10 +63,12 @@
{% } %}
{% if (data.delivery_status) {
if (in_list(["Sent", "Opened", "Clicked"], data.delivery_status)) {
if (in_list(["Sent", "Clicked"], data.delivery_status)) {
var indicator_class = "green";
} else if (data.delivery_status === "Sending") {
var indicator_class = "orange";
} else if (in_list("Opened", "Read", data.delivery_status)) {
var indicator_class = "blue";
} else {
var indicator_class = "red";
}

View file

@ -114,12 +114,12 @@ frappe.ui.form.PrintPreview = Class.extend({
},
set_default_print_language: function () {
var print_format = this.get_print_format();
if (print_format.default_print_language) {
this.lang_code = print_format.default_print_language;
this.language_sel.val(this.lang_code);
} else {
this.language_sel.val(frappe.boot.lang);
this.language_sel.val(frappe.boot.lang);
}
},
multilingual_preview: function () {
@ -155,7 +155,38 @@ frappe.ui.form.PrintPreview = Class.extend({
`);
},
printit: function () {
let print_server ;
var me = this;
frappe.call({
async: false,
"method": "frappe.client.get",
args: {
doctype: "Print Settings",
name: "enable_print_server"
},
callback: function (data) {
print_server = data.message.enable_print_server;
}
});
if(print_server){
frappe.call({
async: false,
"method": "frappe.utils.print_format.print_by_server",
args: {
doctype: me.frm.doc.doctype,
name: me.frm.doc.name,
print_format: me.selected_format(),
no_letterhead: me.with_letterhead()
},
callback: function (data) {
}
});
}else{
this.new_page_preview(true);
}
},
new_page_preview: function (printit) {
var me = this;

View file

@ -34,11 +34,11 @@ frappe.ui.Dialog = frappe.ui.FieldGroup.extend({
// show footer
this.action = this.action || { primary: { }, secondary: { } };
if(this.primary_action || !this.action.primary) {
if(this.primary_action || this.action.primary) {
this.set_primary_action(this.primary_action_label || this.action.primary.label || __("Submit"), this.primary_action || this.action.primary.onsubmit);
}
if (this.secondary_action_label || !this.action.secondary) {
if (this.secondary_action_label || this.action.secondary) {
this.get_close_btn().html(this.secondary_action_label || this.action.secondary.label);
}

View file

@ -408,7 +408,6 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
}
get_visible_columns() {
// return columns according to user_settings
const visible_column_ids = this.datatable.datamanager.getColumns(true).map(col => col.id);
return visible_column_ids
@ -444,7 +443,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
}
get_filter(fieldname) {
const field = this.filters.find(f => f.df.fieldname === fieldname);
const field = (this.filters || []).find(f => f.df.fieldname === fieldname);
if (!field) {
console.warn(`[Query Report] Invalid filter: ${fieldname}`);
}
@ -660,11 +659,6 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
];
}
setup_page_head() {
super.setup_page_head();
this.page.set_title_sub(`<label class='label label-warning text-color'>${__('Beta')}</label>`);
}
setup_report_wrapper() {
if (this.$report) return;

View file

@ -51,9 +51,9 @@ table td.dt-cell {
}
.dt-header {
--header-cell-bg: @panel-bg;
--cell-bg: @panel-bg;
--text-color: @text-muted;
--dt-header-cell-bg: @panel-bg;
--dt-cell-bg: @panel-bg;
--dt-text-color: @text-muted;
.dt-row[data-is-filter] {
display: table-row !important;

View file

@ -6,7 +6,7 @@ from frappe import _
from frappe.modules import get_doc_path
from jinja2 import TemplateNotFound
from frappe.utils import cint, strip_html
from frappe.utils.pdf import get_pdf
from frappe.utils.pdf import get_pdf,cleanup
from PyPDF2 import PdfFileWriter, PdfFileReader
no_cache = 1
@ -52,4 +52,32 @@ def download_pdf(doctype, name, format=None, doc=None, no_letterhead=0):
def report_to_pdf(html, orientation="Landscape"):
frappe.local.response.filename = "report.pdf"
frappe.local.response.filecontent = get_pdf(html, {"orientation": orientation})
frappe.local.response.type = "download"
frappe.local.response.type = "download"
@frappe.whitelist()
def print_by_server(doctype, name, print_format=None, doc=None, no_letterhead=0):
print_settings = frappe.get_doc("Print Settings")
try:
import cups
except ModuleNotFoundError:
frappe.throw("You need to install pycups to use this feature!")
return
try:
cups.setServer(print_settings.server_ip)
cups.setPort(print_settings.port)
conn = cups.Connection()
output = PdfFileWriter()
output = frappe.get_print(doctype, name, print_format, doc=doc, no_letterhead=no_letterhead, as_pdf = True, output = output)
file = os.path.join("/", "tmp", "frappe-pdf-{0}.pdf".format(frappe.generate_hash()))
output.write(open(file,"wb"))
conn.printFile(print_settings.printer_name,file , name, {})
except IOError as e:
if ("ContentNotFoundError" in e.message
or "ContentOperationNotPermittedError" in e.message
or "UnknownContentError" in e.message
or "RemoteHostClosedError" in e.message):
frappe.throw(_("PDF generation failed"))
except cups.IPPError:
frappe.throw(_("Printing failed"))
finally:
cleanup(file,{})