diff --git a/frappe/__init__.py b/frappe/__init__.py
index f6a8b5c2b6..6c3d314370 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -17,7 +17,7 @@ from faker import Faker
from .exceptions import *
from .utils.jinja import (get_jenv, get_template, render_template, get_email_from_template, get_jloader)
-__version__ = '10.1.45'
+__version__ = '10.1.46'
__title__ = "Frappe Framework"
local = Local()
diff --git a/frappe/core/doctype/communication/comment.py b/frappe/core/doctype/communication/comment.py
index 2c7a4bd122..0ceb93219c 100644
--- a/frappe/core/doctype/communication/comment.py
+++ b/frappe/core/doctype/communication/comment.py
@@ -94,7 +94,7 @@ def notify_mentions(doc):
subject = _("{0} mentioned you in a comment").format(sender_fullname)
- recipients = [frappe.db.get_value("User", {"enabled": 1, "name": name, "user_type": "System User"})
+ recipients = [frappe.db.get_value("User", {"enabled": 1, "name": name, "user_type": "System User"}, "email")
for name in mentions]
frappe.sendmail(
recipients=recipients,
diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py
index 175388c933..c5bd1fe78d 100644
--- a/frappe/core/doctype/doctype/doctype.py
+++ b/frappe/core/doctype/doctype/doctype.py
@@ -56,6 +56,7 @@ 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()
@@ -194,6 +195,17 @@ 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:
+ new_options = ""
+ for option in field.options.split("\n"):
+ new_options += option.strip()
+ new_options += "\n"
+ new_options.rstrip("\n")
+ field.options = new_options
+
def validate_series(self, autoname=None, name=None):
"""Validate if `autoname` property is correctly set."""
if not autoname: autoname = self.autoname
@@ -446,9 +458,9 @@ class DocType(Document):
# a DocType's name should not start with a number or underscore
# and should only contain letters, numbers and underscore
if six.PY2:
- is_a_valid_name = re.match("^(?![\W])[^\d_\s][\w -]+$", name)
+ is_a_valid_name = re.match("^(?![\W])[^\d_\s][\w ]+$", name)
else:
- is_a_valid_name = re.match("^(?![\W])[^\d_\s][\w -]+$", name, flags = re.ASCII)
+ is_a_valid_name = re.match("^(?![\W])[^\d_\s][\w ]+$", name, flags = re.ASCII)
if not is_a_valid_name:
frappe.throw(_("DocType's name should start with a letter and it can only consist of letters, numbers, spaces and underscores"), frappe.NameError)
diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py
index 41ead28444..d95117139f 100644
--- a/frappe/core/doctype/user/user.py
+++ b/frappe/core/doctype/user/user.py
@@ -923,10 +923,10 @@ def notify_admin_access_to_system_manager(login_manager=None):
def extract_mentions(txt):
"""Find all instances of @name in the string.
The mentions will be separated by non-word characters or may appear at the start of the string"""
+ txt = txt.replace("
", "
")
txt = re.sub(r'(<[a-zA-Z\/][^>]*>)', '', txt)
return re.findall(r'(?:[^\w\.\-\@]|^)@([\w\.\-\@]*)', txt)
-
def handle_password_test_fail(result):
suggestions = result['feedback']['suggestions'][0] if result['feedback']['suggestions'] else ''
warning = result['feedback']['warning'] if 'warning' in result['feedback'] else ''
diff --git a/frappe/email/doctype/auto_email_report/auto_email_report.py b/frappe/email/doctype/auto_email_report/auto_email_report.py
index 9a9f736800..f896f441f5 100644
--- a/frappe/email/doctype/auto_email_report/auto_email_report.py
+++ b/frappe/email/doctype/auto_email_report/auto_email_report.py
@@ -108,6 +108,7 @@ class AutoEmailReport(Document):
new_row = []
out.append(new_row)
for df in columns:
+ if not row.get(df.fieldname): continue
new_row.append(frappe.format(row[df.fieldname], df, row))
return out
diff --git a/frappe/email/doctype/notification/notification.js b/frappe/email/doctype/notification/notification.js
index bdd3dbbde9..44056955f7 100644
--- a/frappe/email/doctype/notification/notification.js
+++ b/frappe/email/doctype/notification/notification.js
@@ -1,6 +1,16 @@
// Copyright (c) 2018, Frappe Technologies and contributors
// For license information, please see license.txt
+this.frm.add_fetch('sender', 'email_id', 'sender_email');
+
+this.frm.fields_dict.sender.get_query = function(){
+ return {
+ filters: {
+ 'enable_outgoing': 1
+ }
+ }
+};
+
frappe.notification = {
setup_fieldname_select: function(frm) {
// get the doctype to update fields
diff --git a/frappe/email/doctype/notification/notification.json b/frappe/email/doctype/notification/notification.json
index 1652c87d93..845af2b8f1 100644
--- a/frappe/email/doctype/notification/notification.json
+++ b/frappe/email/doctype/notification/notification.json
@@ -509,6 +509,68 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "sender",
+ "fieldtype": "Link",
+ "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": "Sender",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Email Account",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "sender_email",
+ "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": "Sender Email",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Email",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "section_break_9",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1062,7 +1124,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2018-05-31 15:44:23.082691",
+ "modified": "2018-08-29 14:32:02.179599",
"modified_by": "Administrator",
"module": "Email",
"name": "Notification",
diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py
index 66c1642d65..60862b1ff1 100644
--- a/frappe/email/doctype/notification/notification.py
+++ b/frappe/email/doctype/notification/notification.py
@@ -127,14 +127,19 @@ def get_context(context):
doc.set(self.set_property_after_alert, self.property_value)
def send_an_email(self, doc, context):
+ from email.utils import formataddr
subject = self.subject
if "{" in subject:
subject = frappe.render_template(self.subject, context)
attachments = self.get_attachment(doc)
recipients = self.get_list_of_recipients(doc, context)
+ sender = None
+ if self.sender and self.sender_email:
+ sender = formataddr((self.sender, self.sender_email))
frappe.sendmail(recipients=recipients, subject=subject,
+ sender=sender,
message= frappe.render_template(self.message, context),
reference_doctype = doc.doctype,
reference_name = doc.name,
diff --git a/frappe/geo/country_info.json b/frappe/geo/country_info.json
index 6ca03a833c..426467c7b7 100644
--- a/frappe/geo/country_info.json
+++ b/frappe/geo/country_info.json
@@ -2555,7 +2555,7 @@
"currency": "USD",
"currency_fraction": "Cent",
"currency_fraction_units": 100,
- "smallest_currency_fraction_value": 0.05,
+ "smallest_currency_fraction_value": 0.01,
"currency_name": "US Dollar",
"currency_symbol": "$",
"date_format": "mm-dd-yyyy",
diff --git a/frappe/patches.txt b/frappe/patches.txt
index edc41d714d..de46fe64ef 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -9,13 +9,13 @@ execute:frappe.reload_doc('core', 'doctype', 'doctype', force=True) #2017-09-22
execute:frappe.reload_doc('core', 'doctype', 'docfield', force=True) #2018-02-20
execute:frappe.reload_doc('core', 'doctype', 'custom_docperm')
execute:frappe.reload_doc('core', 'doctype', 'docperm') #2018-05-29
+frappe.patches.v8_0.drop_is_custom_from_docperm
execute:frappe.reload_doc('core', 'doctype', 'module_def') #2017-09-22
execute:frappe.reload_doc('core', 'doctype', 'version') #2017-04-01
frappe.patches.v11_0.copy_fetch_data_from_options
frappe.patches.v7_1.rename_scheduler_log_to_error_log
frappe.patches.v6_1.rename_file_data
frappe.patches.v7_0.re_route #2016-06-27
-frappe.patches.v8_0.drop_is_custom_from_docperm
frappe.patches.v8_0.update_records_in_global_search #11-05-2017
frappe.patches.v8_0.update_published_in_global_search
frappe.patches.v11_0.replicate_old_user_permissions
@@ -223,4 +223,5 @@ frappe.patches.v11_0.replicate_old_user_permissions
frappe.patches.v11_0.set_dropbox_file_backup
frappe.patches.v11_0.get_docs_apps_if_not_present
frappe.patches.v10_0.set_default_locking_time
-frappe.patches.v11_0.rename_google_maps_doctype
\ No newline at end of file
+frappe.patches.v11_0.rename_google_maps_doctype
+frappe.patches.v10_0.modify_smallest_currency_fraction
diff --git a/frappe/patches/v10_0/modify_smallest_currency_fraction.py b/frappe/patches/v10_0/modify_smallest_currency_fraction.py
new file mode 100644
index 0000000000..c9ae477359
--- /dev/null
+++ b/frappe/patches/v10_0/modify_smallest_currency_fraction.py
@@ -0,0 +1,7 @@
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+import frappe
+
+def execute():
+ frappe.db.set_value('Currency', 'USD', 'smallest_currency_fraction_value', '0.01')
\ No newline at end of file
diff --git a/frappe/public/js/frappe/form/footer/timeline.js b/frappe/public/js/frappe/form/footer/timeline.js
index 998b19584f..efa581f8d7 100644
--- a/frappe/public/js/frappe/form/footer/timeline.js
+++ b/frappe/public/js/frappe/form/footer/timeline.js
@@ -118,7 +118,6 @@ frappe.ui.form.Timeline = Class.extend({
this.wrapper.toggle(true);
this.list.empty();
this.comment_area.val('');
-
var communications = this.get_communications(true);
var views = this.get_view_logs();
@@ -180,7 +179,6 @@ frappe.ui.form.Timeline = Class.extend({
} else {
var $edit_btn = $(this);
var content = $timeline_item.find('.timeline-item-content').html();
-
$edit_btn
.text("Save")
.find('i')
@@ -300,7 +298,6 @@ frappe.ui.form.Timeline = Class.extend({
c.original_content = c.content;
c.content = frappe.utils.toggle_blockquote(c.content);
}
-
if(!frappe.utils.is_html(c.content)) {
c.content_html = frappe.markdown(__(c.content));
} else {
@@ -314,7 +311,17 @@ frappe.ui.form.Timeline = Class.extend({
// avoid adding tag a 2nd time
!c.content_html.match(/(^|\W)(@[^\s]+)<\/b>/)
) {
- c.content_html = c.content_html.replace(/(^|\W)(@[^\s]+)/g, "$1$2");
+ /*
+ Replace the email ids by only displaying the string which
+ occurs before the second `@` to enhance the mentions.
+ Eg.
+ @abc@a-example.com will be converted to
+ @abc with the below line of code.
+ */
+
+ c.content_html = c.content_html.replace(/(<[a][^>]*>)/g, "");
+ // bold the @mentions
+ c.content_html = c.content_html.replace(/(@[^\s@]*)@[^\s@|<]*/g, "$1");
}
if (this.is_communication_or_comment(c)) {
@@ -670,7 +677,7 @@ frappe.ui.form.Timeline = Class.extend({
var valid_users = Object.keys(frappe.boot.user_info)
.filter(user => !["Administrator", "Guest"].includes(user));
- return valid_users.map(user => frappe.boot.user_info[user].name);
+ return valid_users.map(user => frappe.boot.user_info[user].email);
},
setup_comment_like: function() {