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 %} -
+