diff --git a/frappe/contacts/address_and_contact.py b/frappe/contacts/address_and_contact.py index 38d292e9b4..6523b0b1e5 100644 --- a/frappe/contacts/address_and_contact.py +++ b/frappe/contacts/address_and_contact.py @@ -152,3 +152,11 @@ def filter_dynamic_link_doctypes(doctype, txt, searchfield, start, page_len, fil valid_doctypes = [[doctype] for doctype in valid_doctypes] return valid_doctypes + +def set_link_title(doc): + if not doc.links: + return + for link in doc.links: + if not link.link_title: + linked_doc = frappe.get_doc(link.link_doctype, link.link_name) + link.link_title = linked_doc.get("title_field") or linked_doc.get("name") diff --git a/frappe/contacts/doctype/address/address.py b/frappe/contacts/doctype/address/address.py index c705f972d3..57ed4e937f 100644 --- a/frappe/contacts/doctype/address/address.py +++ b/frappe/contacts/doctype/address/address.py @@ -15,6 +15,7 @@ from frappe.model.naming import make_autoname from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_links from six import iteritems, string_types from past.builtins import cmp +from frappe.contacts.address_and_contact import set_link_title import functools @@ -39,6 +40,7 @@ class Address(Document): def validate(self): self.link_address() self.validate_reference() + set_link_title(self) deduplicate_dynamic_links(self) def link_address(self): diff --git a/frappe/contacts/doctype/contact/contact.py b/frappe/contacts/doctype/contact/contact.py index 987fad3829..0e0d9aeabc 100644 --- a/frappe/contacts/doctype/contact/contact.py +++ b/frappe/contacts/doctype/contact/contact.py @@ -10,6 +10,7 @@ from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_li from six import iteritems from past.builtins import cmp from frappe.model.naming import append_number_if_name_exists +from frappe.contacts.address_and_contact import set_link_title import functools @@ -31,6 +32,7 @@ class Contact(Document): if self.email_id: self.email_id = self.email_id.strip() self.set_user() + set_link_title(self) if self.email_id and not self.image: self.image = has_gravatar(self.email_id) diff --git a/frappe/core/doctype/prepared_report/prepared_report.py b/frappe/core/doctype/prepared_report/prepared_report.py index 847f1a840b..29c069515f 100644 --- a/frappe/core/doctype/prepared_report/prepared_report.py +++ b/frappe/core/doctype/prepared_report/prepared_report.py @@ -54,14 +54,14 @@ def run_background(prepared_report): instance.status = "Completed" instance.columns = json.dumps(result["columns"]) instance.report_end_time = frappe.utils.now() - instance.save() + instance.save(ignore_permissions=True) except Exception: frappe.log_error(frappe.get_traceback()) instance = frappe.get_doc("Prepared Report", prepared_report) instance.status = "Error" instance.error_message = frappe.get_traceback() - instance.save() + instance.save(ignore_permissions=True) frappe.publish_realtime( 'report_generated', diff --git a/frappe/desk/form/document_follow.py b/frappe/desk/form/document_follow.py index 20cd1ec9b6..333e9e1333 100644 --- a/frappe/desk/form/document_follow.py +++ b/frappe/desk/form/document_follow.py @@ -275,7 +275,7 @@ def get_filters(search_by, name, frequency, user): elif frequency == "Hourly": filters = [ [search_by, "=", name], - ["modified", ">", frappe.utils.add_to_date(frappe.utils.now_datetime(), 0, 0, 0, -1)], + ["modified", ">", frappe.utils.add_to_date(frappe.utils.now_datetime(), hours=-1)], ["modified", "<", frappe.utils.now_datetime()], ["modified_by", "!=", user] ] diff --git a/frappe/desk/page/setup_wizard/setup_wizard.py b/frappe/desk/page/setup_wizard/setup_wizard.py index cf8f5f502b..a18d4df9c4 100755 --- a/frappe/desk/page/setup_wizard/setup_wizard.py +++ b/frappe/desk/page/setup_wizard/setup_wizard.py @@ -389,7 +389,7 @@ def make_records(records, debug=False): # pass DuplicateEntryError and continue if e.args and e.args[0]==doc.doctype and e.args[1]==doc.name: # make sure DuplicateEntryError is for the exact same doc and not a related doc - pass + frappe.clear_messages() else: raise diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py index 561cd680b6..0890e2ad7a 100644 --- a/frappe/desk/query_report.py +++ b/frappe/desk/query_report.py @@ -282,6 +282,10 @@ def export_query(): filters = json.loads(data["filters"]) if isinstance(data.get("report_name"), string_types): report_name = data["report_name"] + frappe.permissions.can_export( + frappe.get_cached_value('Report', report_name, 'ref_doctype'), + raise_exception=True + ) if isinstance(data.get("file_format_type"), string_types): file_format_type = data["file_format_type"] diff --git a/frappe/geo/country_info.json b/frappe/geo/country_info.json index bdd6414730..7a6ba56929 100644 --- a/frappe/geo/country_info.json +++ b/frappe/geo/country_info.json @@ -2330,6 +2330,7 @@ }, "Suriname": { "code": "sr", + "currency": "SRD", "currency_fraction": "Cent", "currency_fraction_units": 100, "currency_symbol": "$", diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py index a373554696..12c57f2780 100644 --- a/frappe/model/rename_doc.py +++ b/frappe/model/rename_doc.py @@ -161,7 +161,7 @@ def validate_rename(doctype, new, meta, merge, force, ignore_permissions): if (not merge) and exists: frappe.msgprint(_("Another {0} with name {1} exists, select another name").format(doctype, new), raise_exception=1) - if not (ignore_permissions or frappe.has_permission(doctype, "write")): + if not (ignore_permissions or frappe.permissions.has_permission(doctype, "write", raise_exception=False)): frappe.msgprint(_("You need write permission to rename"), raise_exception=1) if not (force or ignore_permissions) and not meta.allow_rename: diff --git a/frappe/patches/v11_0/create_contact_for_user.py b/frappe/patches/v11_0/create_contact_for_user.py index d5e9c87e8b..c91caf9189 100644 --- a/frappe/patches/v11_0/create_contact_for_user.py +++ b/frappe/patches/v11_0/create_contact_for_user.py @@ -6,6 +6,7 @@ import re def execute(): """ Create Contact for each User if not present """ frappe.reload_doc('contacts', 'doctype', 'contact') + frappe.reload_doc('core', 'doctype', 'dynamic_link') users = frappe.get_all('User', filters={"name": ('not in', 'Administrator, Guest')}, fields=["*"]) for user in users: diff --git a/frappe/permissions.py b/frappe/permissions.py index 3809bb3e9c..e5aa31d139 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -25,16 +25,18 @@ def print_has_permission_check_logs(func): frappe.flags['has_permission_check_logs'] = [] result = func(*args, **kwargs) self_perm_check = True if not kwargs.get('user') else kwargs.get('user') == frappe.session.user + raise_exception = False if kwargs.get('raise_exception') == False else True + # print only if access denied # and if user is checking his own permission - if not result and self_perm_check: + if not result and self_perm_check and raise_exception: msgprint(('
').join(frappe.flags.get('has_permission_check_logs'))) frappe.flags.pop('has_permission_check_logs', None) return result return inner @print_has_permission_check_logs -def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None): +def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None, raise_exception=True): """Returns True if user has permission `ptype` for given `doctype`. If `doc` is passed, it also checks user, share and owner permissions. diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index eee20b64e7..27b483b7aa 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -269,7 +269,10 @@ frappe.Application = Class.extend({ refresh_notifications: function() { var me = this; if(frappe.session_alive && frappe.boot && frappe.boot.home_page !== 'setup-wizard') { - return frappe.call({ + if (this._refresh_notifications) { + this._refresh_notifications.abort(); + } + this._refresh_notifications = frappe.call({ type: 'GET', method: "frappe.desk.notifications.get_notifications", callback: function(r) { diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 485f26f952..5e7e79312f 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -970,6 +970,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { { label: __('Export'), action: () => this.export_report(), + condition: () => frappe.model.can_export(this.report_doc.ref_doctype), standard: true }, { @@ -991,9 +992,11 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { change: () => { let doctype = d.get_value('doctype'); frappe.model.with_doctype(doctype, () => { - let fields = frappe.meta.get_docfields(doctype) + let options = frappe.meta.get_docfields(doctype) + .filter(frappe.model.is_value_type) .map(df => ({ label: df.label, value: df.fieldname })); - d.set_df_property('field', 'options', fields); + + d.set_df_property('field', 'options', options); }); } diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 84ea04b593..bad5407b4b 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -108,6 +108,11 @@ def add_years(date, years): def date_diff(string_ed_date, string_st_date): return (getdate(string_ed_date) - getdate(string_st_date)).days +def month_diff(string_ed_date, string_st_date): + ed_date = getdate(string_ed_date) + st_date = getdate(string_st_date) + return (ed_date.year - st_date.year) * 12 + ed_date.month - st_date.month + 1 + def time_diff(string_ed_date, string_st_date): return get_datetime(string_ed_date) - get_datetime(string_st_date)