Merge branch 'master' into develop
This commit is contained in:
commit
bfc25ad1e5
24 changed files with 200 additions and 75 deletions
|
|
@ -16,6 +16,7 @@ from faker import Faker
|
|||
# public
|
||||
from .exceptions import *
|
||||
from .utils.jinja import (get_jenv, get_template, render_template, get_email_from_template, get_jloader)
|
||||
from .utils.error import get_frame_locals
|
||||
|
||||
# Hamless for Python 3
|
||||
# For Python 2 set default encoding to utf-8
|
||||
|
|
@ -23,7 +24,7 @@ if sys.version[0] == '2':
|
|||
reload(sys)
|
||||
sys.setdefaultencoding("utf-8")
|
||||
|
||||
__version__ = '11.1.5'
|
||||
__version__ = '11.1.6'
|
||||
__title__ = "Frappe Framework"
|
||||
|
||||
local = Local()
|
||||
|
|
@ -273,7 +274,7 @@ def errprint(msg):
|
|||
if not request or (not "cmd" in local.form_dict) or conf.developer_mode:
|
||||
print(msg)
|
||||
|
||||
error_log.append(msg)
|
||||
error_log.append({"exc": msg, "locals": get_frame_locals()})
|
||||
|
||||
def log(msg):
|
||||
"""Add to `debug_log`.
|
||||
|
|
|
|||
|
|
@ -307,7 +307,8 @@ def set_incoming_outgoing_accounts(doc):
|
|||
|
||||
doc.outgoing_email_account = frappe.db.get_value("Email Account",
|
||||
{"append_to": doc.reference_doctype, "enable_outgoing": 1},
|
||||
["email_id", "always_use_account_email_id_as_sender", "name"], as_dict=True)
|
||||
["email_id", "always_use_account_email_id_as_sender", "name",
|
||||
"always_use_account_name_as_sender_name"], as_dict=True)
|
||||
|
||||
if not doc.incoming_email_account:
|
||||
doc.incoming_email_account = frappe.db.get_value("Email Account",
|
||||
|
|
@ -317,12 +318,14 @@ def set_incoming_outgoing_accounts(doc):
|
|||
# if from address is not the default email account
|
||||
doc.outgoing_email_account = frappe.db.get_value("Email Account",
|
||||
{"email_id": doc.sender, "enable_outgoing": 1},
|
||||
["email_id", "always_use_account_email_id_as_sender", "name", "send_unsubscribe_message"], as_dict=True) or frappe._dict()
|
||||
["email_id", "always_use_account_email_id_as_sender", "name",
|
||||
"send_unsubscribe_message", "always_use_account_name_as_sender_name"], as_dict=True) or frappe._dict()
|
||||
|
||||
if not doc.outgoing_email_account:
|
||||
doc.outgoing_email_account = frappe.db.get_value("Email Account",
|
||||
{"default_outgoing": 1, "enable_outgoing": 1},
|
||||
["email_id", "always_use_account_email_id_as_sender", "name", "send_unsubscribe_message"],as_dict=True) or frappe._dict()
|
||||
["email_id", "always_use_account_email_id_as_sender", "name",
|
||||
"send_unsubscribe_message", "always_use_account_name_as_sender_name"],as_dict=True) or frappe._dict()
|
||||
|
||||
if doc.sent_or_received == "Sent":
|
||||
doc.db_set("email_account", doc.outgoing_email_account.name)
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ class DocType(Document):
|
|||
self.permissions = []
|
||||
|
||||
self.scrub_field_names()
|
||||
self.scrub_options_in_select()
|
||||
self.set_default_in_list_view()
|
||||
self.set_default_translatable()
|
||||
self.validate_series()
|
||||
|
|
@ -202,17 +201,6 @@ class DocType(Document):
|
|||
# unique is automatically an index
|
||||
if d.unique: d.search_index = 0
|
||||
|
||||
def scrub_options_in_select(self):
|
||||
"""Strip options for whitespaces"""
|
||||
for field in self.fields:
|
||||
if field.fieldtype == "Select" and field.options is not None:
|
||||
options_list = []
|
||||
for i, option in enumerate(field.options.split("\n")):
|
||||
_option = option.strip()
|
||||
if i==0 or _option:
|
||||
options_list.append(_option)
|
||||
field.options = '\n'.join(options_list)
|
||||
|
||||
def validate_series(self, autoname=None, name=None):
|
||||
"""Validate if `autoname` property is correctly set."""
|
||||
if not autoname: autoname = self.autoname
|
||||
|
|
@ -705,6 +693,20 @@ def validate_fields(meta):
|
|||
frappe.throw(_('DocType <b>{0}</b> provided for the field <b>{1}</b> must have atleast one Link field')
|
||||
.format(doctype, docfield.fieldname), frappe.ValidationError)
|
||||
|
||||
def scrub_options_in_select(field):
|
||||
"""Strip options for whitespaces"""
|
||||
|
||||
if field.fieldtype == "Select" and field.options is not None:
|
||||
options_list = []
|
||||
for i, option in enumerate(field.options.split("\n")):
|
||||
_option = option.strip()
|
||||
if i==0 or _option:
|
||||
options_list.append(_option)
|
||||
field.options = '\n'.join(options_list)
|
||||
|
||||
def scrub_fetch_from(field):
|
||||
if hasattr(field, 'fetch_from') and getattr(field, 'fetch_from'):
|
||||
field.fetch_from = field.fetch_from.strip('\n').strip()
|
||||
|
||||
fields = meta.get("fields")
|
||||
fieldname_list = [d.fieldname for d in fields]
|
||||
|
|
@ -734,6 +736,8 @@ def validate_fields(meta):
|
|||
check_unique_and_text(d)
|
||||
check_illegal_depends_on_conditions(d)
|
||||
check_table_multiselect_option(d)
|
||||
scrub_options_in_select(d)
|
||||
scrub_fetch_from(d)
|
||||
|
||||
check_fold(fields)
|
||||
check_search_fields(meta, fields)
|
||||
|
|
|
|||
|
|
@ -3,11 +3,22 @@
|
|||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, json
|
||||
import frappe, json, re
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
|
||||
class Language(Document):
|
||||
pass
|
||||
def validate(self):
|
||||
validate_with_regex(self.language_code, "Language Code")
|
||||
|
||||
def before_rename(self, old, new, merge=False):
|
||||
validate_with_regex(new, "Name")
|
||||
|
||||
def validate_with_regex(name, label):
|
||||
pattern = re.compile("^[a-zA-Z]+[-_]*[a-zA-Z]+$")
|
||||
if not pattern.match(name):
|
||||
frappe.throw(_("""{0} must begin and end with a letter and can only contain letters,
|
||||
hyphen or underscore.""").format(label))
|
||||
|
||||
def export_languages_json():
|
||||
'''Export list of all languages'''
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"search_index": 1,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
|
|
@ -222,7 +222,7 @@
|
|||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-11-12 16:26:12.362352",
|
||||
"modified": "2019-02-13 22:58:27.428741",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "User Permission",
|
||||
|
|
|
|||
|
|
@ -881,9 +881,14 @@ class Database(object):
|
|||
|
||||
def get_descendants(self, doctype, name):
|
||||
'''Return descendants of the current record'''
|
||||
lft, rgt = self.get_value(doctype, name, ('lft', 'rgt'))
|
||||
return self.sql_list('''select name from `tab{doctype}`
|
||||
where lft > {lft} and rgt < {rgt}'''.format(doctype=doctype, lft=lft, rgt=rgt))
|
||||
node_location_indexes = self.get_value(doctype, name, ('lft', 'rgt'))
|
||||
if node_location_indexes:
|
||||
lft, rgt = node_location_indexes
|
||||
return self.sql_list('''select name from `tab{doctype}`
|
||||
where lft > {lft} and rgt < {rgt}'''.format(doctype=doctype, lft=lft, rgt=rgt))
|
||||
else:
|
||||
# when document does not exist
|
||||
return []
|
||||
|
||||
def is_missing_table_or_column(self, e):
|
||||
return self.is_missing_column(e) or self.is_missing_table(e)
|
||||
|
|
|
|||
|
|
@ -190,30 +190,34 @@ def run(report_name, filters=None, user=None):
|
|||
|
||||
def get_prepared_report_result(report, filters, dn="", user=None):
|
||||
latest_report_data = {}
|
||||
# Only look for completed prepared reports with given filters.
|
||||
doc_list = frappe.get_all("Prepared Report",
|
||||
filters={"status": "Completed", "report_name": report.name, "filters": filters, "owner": user})
|
||||
|
||||
doc = None
|
||||
if len(doc_list):
|
||||
if dn:
|
||||
# Get specified dn
|
||||
doc = frappe.get_doc("Prepared Report", dn)
|
||||
else:
|
||||
if dn:
|
||||
# Get specified dn
|
||||
doc = frappe.get_doc("Prepared Report", dn)
|
||||
else:
|
||||
# Only look for completed prepared reports with given filters.
|
||||
doc_list = frappe.get_all("Prepared Report", filters={"status": "Completed", "filters": json.dumps(filters), "owner": user})
|
||||
if doc_list:
|
||||
# Get latest
|
||||
doc = frappe.get_doc("Prepared Report", doc_list[0])
|
||||
|
||||
# Prepared Report data is stored in a GZip compressed JSON file
|
||||
attached_file_name = frappe.db.get_value("File", {"attached_to_doctype": doc.doctype, "attached_to_name":doc.name}, "name")
|
||||
attached_file = frappe.get_doc('File', attached_file_name)
|
||||
compressed_content = attached_file.get_content()
|
||||
uncompressed_content = gzip_decompress(compressed_content)
|
||||
data = json.loads(uncompressed_content)
|
||||
if data:
|
||||
latest_report_data = {
|
||||
"columns": json.loads(doc.columns) if doc.columns else data[0],
|
||||
"result": data
|
||||
}
|
||||
if doc:
|
||||
try:
|
||||
# Prepared Report data is stored in a GZip compressed JSON file
|
||||
attached_file_name = frappe.db.get_value("File", {"attached_to_doctype": doc.doctype, "attached_to_name":doc.name}, "name")
|
||||
attached_file = frappe.get_doc('File', attached_file_name)
|
||||
compressed_content = attached_file.get_content()
|
||||
uncompressed_content = gzip_decompress(compressed_content)
|
||||
data = json.loads(uncompressed_content)
|
||||
if data:
|
||||
latest_report_data = {
|
||||
"columns": json.loads(doc.columns) if doc.columns else data[0],
|
||||
"result": data
|
||||
}
|
||||
except Exception:
|
||||
frappe.delete_doc("Prepared Report", doc.name)
|
||||
frappe.db.commit()
|
||||
doc = None
|
||||
|
||||
latest_report_data.update({
|
||||
"prepared_report": True,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 1,
|
||||
|
|
@ -1063,6 +1064,40 @@
|
|||
"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": "enable_outgoing",
|
||||
"description": "Uses the Email Address Name mentioned in this Account as the Sender's Name for all emails sent using this Account.",
|
||||
"fieldname": "always_use_account_name_as_sender_name",
|
||||
"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": "Always use Account's Name as Sender's 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,
|
||||
|
|
@ -1563,7 +1598,7 @@
|
|||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-01-30 11:02:41.011412",
|
||||
"modified": "2019-02-12 17:09:50.653403",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Email Account",
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ class EMail:
|
|||
self.reply_to = validate_email_add(strip(self.reply_to) or self.sender, True)
|
||||
|
||||
self.replace_sender()
|
||||
self.replace_sender_name()
|
||||
|
||||
self.recipients = [strip(r) for r in self.recipients]
|
||||
self.cc = [strip(r) for r in self.cc]
|
||||
|
|
@ -188,6 +189,12 @@ class EMail:
|
|||
sender_name, sender_email = parse_addr(self.sender)
|
||||
self.sender = email.utils.formataddr((str(Header(sender_name or self.email_account.name, 'utf-8')), self.email_account.email_id))
|
||||
|
||||
def replace_sender_name(self):
|
||||
if cint(self.email_account.always_use_account_name_as_sender_name):
|
||||
self.set_header('X-Original-From', self.sender)
|
||||
sender_name, sender_email = parse_addr(self.sender)
|
||||
self.sender = email.utils.formataddr((str(Header(self.email_account.name, 'utf-8')), sender_email))
|
||||
|
||||
def set_message_id(self, message_id, is_notification=False):
|
||||
if message_id:
|
||||
self.msg_root["Message-Id"] = '<' + message_id + '>'
|
||||
|
|
|
|||
|
|
@ -109,7 +109,8 @@ def get_default_outgoing_email_account(raise_exception_not_set=True):
|
|||
"mail_password": "Super.Secret.Password",
|
||||
"auto_email_id": "emails@example.com",
|
||||
"email_sender_name": "Example Notifications",
|
||||
"always_use_account_email_id_as_sender": 0
|
||||
"always_use_account_email_id_as_sender": 0,
|
||||
"always_use_account_name_as_sender_name": 0
|
||||
}
|
||||
'''
|
||||
email_account = _get_email_account({"enable_outgoing": 1, "default_outgoing": 1})
|
||||
|
|
@ -128,7 +129,8 @@ def get_default_outgoing_email_account(raise_exception_not_set=True):
|
|||
"login_id": frappe.conf.get("mail_login"),
|
||||
"email_id": frappe.conf.get("auto_email_id") or frappe.conf.get("mail_login") or 'notifications@example.com',
|
||||
"password": frappe.conf.get("mail_password"),
|
||||
"always_use_account_email_id_as_sender": frappe.conf.get("always_use_account_email_id_as_sender", 0)
|
||||
"always_use_account_email_id_as_sender": frappe.conf.get("always_use_account_email_id_as_sender", 0),
|
||||
"always_use_account_name_as_sender_name": frappe.conf.get("always_use_account_name_as_sender_name", 0)
|
||||
})
|
||||
email_account.from_site_config = True
|
||||
email_account.name = frappe.conf.get("email_sender_name") or "Frappe"
|
||||
|
|
@ -182,6 +184,7 @@ class SMTPServer:
|
|||
self.use_tls = self.email_account.use_tls
|
||||
self.sender = self.email_account.email_id
|
||||
self.always_use_account_email_id_as_sender = cint(self.email_account.get("always_use_account_email_id_as_sender"))
|
||||
self.always_use_account_name_as_sender_name = cint(self.email_account.get("always_use_account_name_as_sender_name"))
|
||||
|
||||
@property
|
||||
def sess(self):
|
||||
|
|
|
|||
|
|
@ -665,13 +665,15 @@ Object.assign(frappe.utils, {
|
|||
return `${route[0]} ${route[1]}`;
|
||||
}
|
||||
},
|
||||
report_total_accumulator: function(column, values, type) {
|
||||
if (column.fieldtype == "Percent" || type === "mean") {
|
||||
return values.reduce((a, b) => ({content: a.content + flt(b.content)})).content / values.length;
|
||||
} else if (frappe.model.is_numeric_field(column.fieldtype)) {
|
||||
return values.reduce((a, b) => ({content: a.content + flt(b.content)})).content;
|
||||
report_column_total: function(values, column, type) {
|
||||
if (column.column.fieldtype == "Percent" || type === "mean") {
|
||||
return values.reduce((a, b) => a + flt(b)) / values.length;
|
||||
} else if (column.column.fieldtype == "Int") {
|
||||
return values.reduce((a, b) => a + cint(b));
|
||||
} else if (frappe.model.is_numeric_field(column.column.fieldtype)) {
|
||||
return values.reduce((a, b) => a + flt(b));
|
||||
} else {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -376,9 +376,12 @@ frappe.request.report_error = function(xhr, request_opts) {
|
|||
var data = JSON.parse(xhr.responseText);
|
||||
if (data.exc) {
|
||||
var exc = (JSON.parse(data.exc) || []).join("\n");
|
||||
var locals = (JSON.parse(data.locals) || []).join("\n");
|
||||
delete data.exc;
|
||||
delete data.locals;
|
||||
} else {
|
||||
var exc = "";
|
||||
locals = "";
|
||||
}
|
||||
|
||||
if (exc) {
|
||||
|
|
@ -410,6 +413,9 @@ frappe.request.report_error = function(xhr, request_opts) {
|
|||
'<h5>Error Report</h5>',
|
||||
'<pre>' + exc + '</pre>',
|
||||
'<hr>',
|
||||
'<h5>Locals</h5>',
|
||||
'<pre>' + locals + '</pre>',
|
||||
'<hr>',
|
||||
'<h5>Request Data</h5>',
|
||||
'<pre>' + JSON.stringify(request_opts, null, "\t") + '</pre>',
|
||||
'<hr>',
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ frappe.ui.app_icon = {
|
|||
}
|
||||
});
|
||||
icon = '<object class="app-icon-svg">'+ icon+'</object>';
|
||||
return icon;
|
||||
} else {
|
||||
icon = '<i class="'+ icon+'" title="' + module._label + '" style="'+ icon_style + '"></i>';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -424,7 +424,7 @@ frappe.views.GridReport = Class.extend({
|
|||
}
|
||||
},
|
||||
hooks: {
|
||||
totalAccumulator: frappe.utils.report_total_accumulator
|
||||
columnTotal: frappe.utils.report_column_total
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
cellHeight: 33,
|
||||
showTotalRow: this.raw_data.add_total_row,
|
||||
hooks: {
|
||||
totalAccumulator: frappe.utils.report_total_accumulator
|
||||
columnTotal: frappe.utils.report_column_total
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
|
|||
}
|
||||
},
|
||||
hooks: {
|
||||
totalAccumulator: frappe.utils.report_total_accumulator
|
||||
columnTotal: frappe.utils.report_column_total
|
||||
},
|
||||
headerDropdown: [{
|
||||
label: __('Add Column'),
|
||||
|
|
|
|||
|
|
@ -100,17 +100,20 @@ frappe.views.TreeView = Class.extend({
|
|||
filter.default = frappe.route_options[filter.fieldname]
|
||||
}
|
||||
|
||||
filter.change = function() {
|
||||
var val = this.get_value();
|
||||
me.args[filter.fieldname] = val;
|
||||
if (val) {
|
||||
me.root_label = val;
|
||||
me.page.set_title(val);
|
||||
} else {
|
||||
me.root_label = me.opts.root_label;
|
||||
me.set_title();
|
||||
if(!filter.disable_onchange) {
|
||||
filter.change = function() {
|
||||
filter.on_change && filter.on_change();
|
||||
var val = this.get_value();
|
||||
me.args[filter.fieldname] = val;
|
||||
if (val) {
|
||||
me.root_label = val;
|
||||
me.page.set_title(val);
|
||||
} else {
|
||||
me.root_label = me.opts.root_label;
|
||||
me.set_title();
|
||||
}
|
||||
me.make_tree();
|
||||
}
|
||||
me.make_tree();
|
||||
}
|
||||
|
||||
me.page.add_field(filter);
|
||||
|
|
@ -153,6 +156,12 @@ frappe.views.TreeView = Class.extend({
|
|||
});
|
||||
|
||||
cur_tree = this.tree;
|
||||
this.post_render();
|
||||
},
|
||||
|
||||
post_render: function() {
|
||||
var me = this;
|
||||
me.opts.post_render && me.opts.post_render(me);
|
||||
},
|
||||
|
||||
select_node: function(node) {
|
||||
|
|
@ -219,6 +228,9 @@ frappe.views.TreeView = Class.extend({
|
|||
]
|
||||
|
||||
if(this.opts.toolbar && this.opts.extend_toolbar) {
|
||||
toolbar = toolbar.filter(btn => {
|
||||
return !me.opts.toolbar.find(d => d["label"]==btn["label"]);
|
||||
});
|
||||
return toolbar.concat(this.opts.toolbar)
|
||||
} else if (this.opts.toolbar && !this.opts.extend_toolbar) {
|
||||
return this.opts.toolbar
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
.dt-scrollable {
|
||||
max-height: calc(100vh - 250px);
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
table td.dt-cell {
|
||||
|
|
|
|||
|
|
@ -199,3 +199,14 @@ def clear_old_snapshots():
|
|||
|
||||
def get_error_snapshot_path():
|
||||
return frappe.get_site_path('error-snapshots')
|
||||
|
||||
def get_frame_locals():
|
||||
traceback = sys.exc_info()[2]
|
||||
if traceback:
|
||||
frames = inspect.getinnerframes(traceback, context=0)
|
||||
_locals = ['Locals (most recent call last):']
|
||||
for frame, filename, lineno, function, __, __ in frames:
|
||||
if '/apps/' in filename:
|
||||
_locals.append('File "{}", line {}, in {}\n{}'.format(filename, lineno, function, json.dumps(frame.f_locals, default=str, indent=4)))
|
||||
|
||||
return '\n'.join(_locals)
|
||||
|
|
|
|||
|
|
@ -262,9 +262,20 @@ def get_root_of(doctype):
|
|||
and t1.rgt > t1.lft""".format(doctype, doctype))
|
||||
return result[0][0] if result else None
|
||||
|
||||
def get_ancestors_of(doctype, name):
|
||||
def get_ancestors_of(doctype, name, order_by="lft desc", limit=None):
|
||||
"""Get ancestor elements of a DocType with a tree structure"""
|
||||
lft, rgt = frappe.db.get_value(doctype, name, ["lft", "rgt"])
|
||||
result = frappe.db.sql_list("""select name from `tab{0}`
|
||||
where lft<%s and rgt>%s order by lft desc""".format(doctype), (lft, rgt))
|
||||
|
||||
result = [d["name"] for d in frappe.db.get_list(doctype, {"lft": ["<", lft], "rgt": [">", rgt]},
|
||||
"name", order_by=order_by, limit_page_length=limit)]
|
||||
|
||||
return result or []
|
||||
|
||||
def get_descendants_of(doctype, name, order_by="lft desc", limit=None):
|
||||
'''Return descendants of the current record'''
|
||||
lft, rgt = frappe.db.get_value(doctype, name, ['lft', 'rgt'])
|
||||
|
||||
result = [d["name"] for d in frappe.db.get_list(doctype, {"lft": [">", lft], "rgt": ["<", rgt]},
|
||||
"name", order_by=order_by, limit_page_length=limit)]
|
||||
|
||||
return result or []
|
||||
|
|
|
|||
|
|
@ -104,8 +104,8 @@ def make_logs(response = None):
|
|||
response = frappe.local.response
|
||||
|
||||
if frappe.error_log:
|
||||
# frappe.response['exc'] = json.dumps("\n".join([cstr(d) for d in frappe.error_log]))
|
||||
response['exc'] = json.dumps([frappe.utils.cstr(d) for d in frappe.local.error_log])
|
||||
response['exc'] = json.dumps([frappe.utils.cstr(d["exc"]) for d in frappe.local.error_log])
|
||||
response['locals'] = json.dumps([frappe.utils.cstr(d["locals"]) for d in frappe.local.error_log])
|
||||
|
||||
if frappe.local.message_log:
|
||||
response['_server_messages'] = json.dumps([frappe.utils.cstr(d) for
|
||||
|
|
|
|||
|
|
@ -85,4 +85,9 @@ def get_desk_assets(build_version):
|
|||
}
|
||||
|
||||
def get_build_version():
|
||||
return str(os.path.getmtime(os.path.join(frappe.local.sites_path, '.build')))
|
||||
try:
|
||||
return str(os.path.getmtime(os.path.join(frappe.local.sites_path, '.build')))
|
||||
except OSError:
|
||||
# .build can sometimes not exist
|
||||
# this is not a major problem so send fallback
|
||||
return frappe.utils.random_string(8)
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ def is_visible(df, doc):
|
|||
if df.fieldname in doc.hide_in_print_layout:
|
||||
return False
|
||||
|
||||
if df.permlevel or 0 > 0 and not doc.has_permlevel_access_to(df.fieldname, df):
|
||||
if (df.permlevel or 0) > 0 and not doc.has_permlevel_access_to(df.fieldname, df):
|
||||
return False
|
||||
|
||||
return not doc.is_print_hide(df.fieldname, df)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,12 @@ frappe.ready(function() {
|
|||
.removeClass().addClass('indicator green')
|
||||
.html("{{ _('Password Updated') }}");
|
||||
if(r.message) {
|
||||
frappe.msgprint("{{ _("Password Updated") }}");
|
||||
frappe.msgprint({
|
||||
message: "{{ _("Password Updated") }}",
|
||||
// password is updated successfully
|
||||
// clear any server message
|
||||
clear: true
|
||||
});
|
||||
setTimeout(function() {
|
||||
window.location.href = r.message;
|
||||
}, 2000);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue