diff --git a/.mergify.yml b/.mergify.yml
index d810898eee..b145834cc4 100644
--- a/.mergify.yml
+++ b/.mergify.yml
@@ -1,7 +1,7 @@
pull_request_rules:
- name: Automatic merge on CI success and review
conditions:
- - status-success=Codacy/PR Quality Review
+ - status-success=Sider
- status-success=Semantic Pull Request
- status-success=Travis CI - Pull Request
- status-success=security/snyk - package.json (frappe)
@@ -14,7 +14,7 @@ pull_request_rules:
method: merge
- name: Automatic squash on CI success and review
conditions:
- - status-success=Codacy/PR Quality Review
+ - status-success=Sider
- status-success=Semantic Pull Request
- status-success=Travis CI - Pull Request
- status-success=security/snyk - package.json (frappe)
diff --git a/frappe/cache_manager.py b/frappe/cache_manager.py
index 0c5b5f94b4..78f452db21 100644
--- a/frappe/cache_manager.py
+++ b/frappe/cache_manager.py
@@ -15,7 +15,8 @@ global_cache_keys = ("app_hooks", "installed_apps",
"app_modules", "module_app", "system_settings",
'scheduler_events', 'time_zone', 'webhooks', 'active_domains',
'active_modules', 'assignment_rule', 'server_script_map', 'wkhtmltopdf_version',
- 'domain_restricted_doctypes', 'domain_restricted_pages', 'information_schema:counts')
+ 'domain_restricted_doctypes', 'domain_restricted_pages', 'information_schema:counts',
+ 'sitemap_routes')
user_cache_keys = ("bootinfo", "user_recent", "roles", "user_doc", "lang",
"defaults", "user_permissions", "home_page", "linked_with",
diff --git a/frappe/core/doctype/docfield/docfield.json b/frappe/core/doctype/docfield/docfield.json
index 9b04ebb7ad..4614dd09c4 100644
--- a/frappe/core/doctype/docfield/docfield.json
+++ b/frappe/core/doctype/docfield/docfield.json
@@ -102,6 +102,7 @@
},
{
"default": "0",
+ "depends_on": "eval:!in_list([\"Section Break\", \"Column Break\", \"Button\", \"HTML\"], doc.fieldtype)",
"fieldname": "reqd",
"fieldtype": "Check",
"in_list_view": 1,
@@ -452,7 +453,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-03-16 14:49:49.672099",
+ "modified": "2020-04-15 02:26:03.310781",
"modified_by": "Administrator",
"module": "Core",
"name": "DocField",
diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py
index f970f51419..f7c9cbe28a 100644
--- a/frappe/core/doctype/doctype/doctype.py
+++ b/frappe/core/doctype/doctype/doctype.py
@@ -206,7 +206,7 @@ class DocType(Document):
if d.fieldtype:
if (not getattr(d, "fieldname", None)):
if d.label:
- d.fieldname = d.label.strip().lower().replace(' ','_')
+ d.fieldname = d.label.strip().lower().replace(' ','_').strip('?')
if d.fieldname in restricted:
d.fieldname = d.fieldname + '1'
if d.fieldtype=='Section Break':
@@ -914,7 +914,7 @@ def validate_fields(meta):
if not d.permlevel: d.permlevel = 0
if d.fieldtype not in table_fields: d.allow_bulk_edit = 0
if not d.fieldname:
- d.fieldname = d.fieldname.lower()
+ d.fieldname = d.fieldname.lower().strip('?')
check_illegal_characters(d.fieldname)
check_invalid_fieldnames(meta.get("name"), d.fieldname)
diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py
index 68848d26f6..7d081953dd 100644
--- a/frappe/custom/doctype/customize_form/customize_form.py
+++ b/frappe/custom/doctype/customize_form/customize_form.py
@@ -208,9 +208,11 @@ class CustomizeForm(Document):
self.validate_fieldtype_change(df, meta_df[0].get(property), df.get(property))
elif property == "allow_on_submit" and df.get(property):
- frappe.msgprint(_("Row {0}: Not allowed to enable Allow on Submit for standard fields")\
- .format(df.idx))
- continue
+ if not frappe.db.get_value("DocField",
+ {"parent": self.doc_type, "fieldname": df.fieldname}, "allow_on_submit"):
+ frappe.msgprint(_("Row {0}: Not allowed to enable Allow on Submit for standard fields")\
+ .format(df.idx))
+ continue
elif property == "reqd" and \
((frappe.db.get_value("DocField",
@@ -369,7 +371,12 @@ class CustomizeForm(Document):
for allowed_changes in allowed_fieldtype_change:
if (old_value in allowed_changes and new_value in allowed_changes):
allowed = True
- if frappe.db.type_map.get(old_value)[1] > frappe.db.type_map.get(new_value)[1]:
+ old_value_length = cint(frappe.db.type_map.get(old_value)[1])
+ new_value_length = cint(frappe.db.type_map.get(new_value)[1])
+
+ # Ignore fieldtype check validation if new field type has unspecified maxlength
+ # Changes like DATA to TEXT, where new_value_lenth equals 0 will not be validated
+ if new_value_length and (old_value_length > new_value_length):
self.check_length_for_fieldtypes.append({'df': df, 'old_value': old_value})
self.validate_fieldtype_length()
else:
@@ -381,7 +388,7 @@ class CustomizeForm(Document):
def validate_fieldtype_length(self):
for field in self.check_length_for_fieldtypes:
df = field.get('df')
- max_length = frappe.db.type_map.get(df.fieldtype)[1]
+ max_length = cint(frappe.db.type_map.get(df.fieldtype)[1])
fieldname = df.fieldname
docs = frappe.db.sql('''
SELECT name, {fieldname}, LENGTH({fieldname}) AS len
diff --git a/frappe/custom/doctype/customize_form_field/customize_form_field.json b/frappe/custom/doctype/customize_form_field/customize_form_field.json
index 34778a76e9..350d159541 100644
--- a/frappe/custom/doctype/customize_form_field/customize_form_field.json
+++ b/frappe/custom/doctype/customize_form_field/customize_form_field.json
@@ -93,6 +93,7 @@
},
{
"default": "0",
+ "depends_on": "eval:!in_list([\"Section Break\", \"Column Break\", \"Button\", \"HTML\"], doc.fieldtype)",
"fieldname": "reqd",
"fieldtype": "Check",
"label": "Mandatory",
@@ -385,7 +386,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-04-07 14:53:40.619043",
+ "modified": "2020-04-15 02:26:59.673750",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customize Form Field",
diff --git a/frappe/desk/desktop.py b/frappe/desk/desktop.py
index 1a110c46d9..f4a15930c4 100644
--- a/frappe/desk/desktop.py
+++ b/frappe/desk/desktop.py
@@ -278,9 +278,13 @@ def get_table_with_counts():
def get_custom_reports_and_doctypes(module):
return [
_dict({
- "label": "Custom",
- "links": get_custom_doctype_list(module) + get_custom_report_list(module)
- })
+ "label": _("Custom Documents"),
+ "links": get_custom_doctype_list(module)
+ }),
+ _dict({
+ "label": _("Custom Reports"),
+ "links": get_custom_report_list(module)
+ }),
]
def get_custom_doctype_list(module):
diff --git a/frappe/email/__init__.py b/frappe/email/__init__.py
index f99536f9a8..d58b35040e 100644
--- a/frappe/email/__init__.py
+++ b/frappe/email/__init__.py
@@ -65,7 +65,7 @@ def get_communication_doctype(doctype, txt, searchfield, start, page_len, filter
com_doctypes = []
if len(txt)<2:
- for name in ["Customer", "Supplier"]:
+ for name in frappe.get_hooks("communication_doctypes"):
try:
module = load_doctype_module(name, suffix='_dashboard')
if hasattr(module, 'get_data'):
diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py
index 13b2b61bef..9ab1ef7799 100644
--- a/frappe/model/base_document.py
+++ b/frappe/model/base_document.py
@@ -506,9 +506,13 @@ class BaseDocument(object):
fetch_from_fieldname = _df.fetch_from.split('.')[-1]
value = values[fetch_from_fieldname]
if _df.fieldtype == 'Small Text' or _df.fieldtype == 'Text' or _df.fieldtype == 'Data':
- fetch_from_df = frappe.get_meta(doctype).get_field(fetch_from_fieldname)
- fetch_from_ft = fetch_from_df.get('fieldtype')
+ if fetch_from_fieldname in default_fields:
+ from frappe.model.meta import get_default_df
+ fetch_from_df = get_default_df(fetch_from_fieldname)
+ else:
+ fetch_from_df = frappe.get_meta(doctype).get_field(fetch_from_fieldname)
+ fetch_from_ft = fetch_from_df.get('fieldtype')
if fetch_from_ft == 'Text Editor' and value:
value = unescape_html(strip_html(value))
setattr(self, _df.fieldname, value)
diff --git a/frappe/public/js/frappe/chat.js b/frappe/public/js/frappe/chat.js
index 810de89874..8b1c09ac93 100644
--- a/frappe/public/js/frappe/chat.js
+++ b/frappe/public/js/frappe/chat.js
@@ -1566,7 +1566,11 @@ class extends Component {
const alert = // TODO: ellipses content
`
- ${frappe.user.first_name(r.user)}: ${r.content}
+
+
+
+
+ ${frappe.user.first_name(r.user)}: ${r.content}
`
frappe.show_alert(alert, 15, {
@@ -1575,6 +1579,11 @@ class extends Component {
this.base.firstChild._component.toggle()
}.bind(this, r)
})
+ frappe.notify(`${frappe.user.first_name(r.user)}`, {
+ body: r.content,
+ icon: frappe.user.image(r.user),
+ tag: r.user
+ })
}
if ( r.room === state.room.name ) {
diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js
index b55c822ba6..e714418375 100644
--- a/frappe/public/js/frappe/form/form.js
+++ b/frappe/public/js/frappe/form/form.js
@@ -1052,7 +1052,7 @@ frappe.ui.form.Form = class FrappeForm {
}
is_dirty() {
- return this.doc.__unsaved;
+ return !!this.doc.__unsaved;
}
is_new() {
diff --git a/frappe/public/js/frappe/form/save.js b/frappe/public/js/frappe/form/save.js
index fbc35634f4..d40b3ed341 100644
--- a/frappe/public/js/frappe/form/save.js
+++ b/frappe/public/js/frappe/form/save.js
@@ -21,7 +21,7 @@ frappe.ui.form.save = function (frm, action, callback, btn) {
remove_empty_rows();
$(frm.wrapper).addClass('validated-form');
- if (check_mandatory()) {
+ if (frm.is_dirty() && check_mandatory()) {
_call({
method: "frappe.desk.form.save.savedocs",
args: { doc: frm.doc, action: action },
@@ -36,6 +36,7 @@ frappe.ui.form.save = function (frm, action, callback, btn) {
freeze_message: freeze_message
});
} else {
+ frappe.show_alert({message: __("Document not updated"), indicator: "yellow"});
$(btn).prop("disabled", false);
}
};
diff --git a/frappe/public/js/frappe/ui/group_by/group_by.js b/frappe/public/js/frappe/ui/group_by/group_by.js
index 6936f25c18..dc81bbdf20 100644
--- a/frappe/public/js/frappe/ui/group_by/group_by.js
+++ b/frappe/public/js/frappe/ui/group_by/group_by.js
@@ -92,7 +92,6 @@ frappe.ui.GroupBy = class {
}
apply_settings(settings) {
-
if (!settings.group_by.startsWith('`tab')) {
settings.group_by = '`tab' + this.doctype + '`.`' + settings.group_by + '`';
}
diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js
index a2b03f180e..0f27e97178 100644
--- a/frappe/public/js/frappe/utils/utils.js
+++ b/frappe/public/js/frappe/utils/utils.js
@@ -675,7 +675,9 @@ Object.assign(frappe.utils, {
return __(frappe.utils.to_title_case(route[0], true));
},
report_column_total: function(values, column, type) {
- if (values.length > 0) {
+ if (column.column.disable_total) {
+ return '';
+ } else if (values.length > 0) {
if (column.column.fieldtype == "Percent" || type === "mean") {
return values.reduce((a, b) => a + flt(b)) / values.length;
} else if (column.column.fieldtype == "Int") {
diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js
index b479c4c101..43540f449d 100644
--- a/frappe/public/js/frappe/views/reports/report_view.js
+++ b/frappe/public/js/frappe/views/reports/report_view.js
@@ -837,6 +837,9 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
fieldtype: 'MultiCheck',
columns: 2,
options: columns[this.doctype]
+ .filter(df => {
+ return !df.hidden;
+ })
.map(df => ({
label: __(df.label),
value: df.fieldname,
@@ -858,6 +861,9 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
fieldtype: 'MultiCheck',
columns: 2,
options: columns[cdt]
+ .filter(df => {
+ return !df.hidden;
+ })
.map(df => ({
label: __(df.label),
value: df.fieldname,
diff --git a/frappe/public/js/frappe/web_form/webform_script.js b/frappe/public/js/frappe/web_form/webform_script.js
index 7bf7162101..688c0938c4 100644
--- a/frappe/public/js/frappe/web_form/webform_script.js
+++ b/frappe/public/js/frappe/web_form/webform_script.js
@@ -2,13 +2,13 @@ import WebFormList from './web_form_list'
import WebForm from './web_form'
frappe.ready(function() {
+ let query_params = frappe.utils.get_query_params();
let wrapper = $(".web-form-wrapper");
- let is_list = parseInt(wrapper.data('is-list'));
+ let is_list = parseInt(wrapper.data('is-list')) || query_params.is_list;
let webform_doctype = wrapper.data('web-form-doctype');
let webform_name = wrapper.data('web-form');
let login_required = parseInt(wrapper.data('login-required'));
let allow_delete = parseInt(wrapper.data('allow-delete'));
- let query_params = frappe.utils.get_query_params();
let doc_name = query_params.name || '';
let is_new = query_params.new;
@@ -38,7 +38,7 @@ frappe.ready(function() {
settings: {
allow_delete
}
- })
+ });
}
function show_form() {
diff --git a/frappe/templates/base.html b/frappe/templates/base.html
index 1c5f286442..2a241c4843 100644
--- a/frappe/templates/base.html
+++ b/frappe/templates/base.html
@@ -62,7 +62,11 @@
{%- endblock -%}
{%- block navbar -%}
- {% include "templates/includes/navbar/navbar.html" %}
+ {%- if navbar_content -%}
+ {{ navbar_content }}
+ {%- else -%}
+ {% include "templates/includes/navbar/navbar.html" %}
+ {%- endif -%}
{%- endblock -%}
{% block content %}
@@ -70,7 +74,11 @@
{% endblock %}
{%- block footer -%}
- {% include "templates/includes/footer/footer.html" %}
+ {%- if footer_content -%}
+ {{ footer_content }}
+ {%- else -%}
+ {% include "templates/includes/footer/footer.html" %}
+ {%- endif -%}
{%- endblock -%}
{% block base_scripts %}
diff --git a/frappe/templates/web.html b/frappe/templates/web.html
index e61672124a..d2d38a6320 100644
--- a/frappe/templates/web.html
+++ b/frappe/templates/web.html
@@ -13,7 +13,7 @@
{% block page_container %}
-
+