From c7a26af7a2c661e0fc747c774cad3ffe4ac011d0 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 6 May 2019 15:12:33 +0530 Subject: [PATCH 01/12] fix: link_title not getting set in address and contact --- frappe/contacts/doctype/address/address.py | 13 +++++++++++++ frappe/contacts/doctype/contact/contact.py | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/frappe/contacts/doctype/address/address.py b/frappe/contacts/doctype/address/address.py index c705f972d3..31f7ae766a 100644 --- a/frappe/contacts/doctype/address/address.py +++ b/frappe/contacts/doctype/address/address.py @@ -39,6 +39,7 @@ class Address(Document): def validate(self): self.link_address() self.validate_reference() + self.set_link_title() deduplicate_dynamic_links(self) def link_address(self): @@ -53,6 +54,18 @@ class Address(Document): return False + def set_link_title(self): + if not self.links: + return + else: + for address in self.links: + if not address.link_title: + linked_doc = frappe.get_doc(address.link_doctype, address.link_name) + try: + address.link_title = linked_doc.title_field + except AttributeError: + address.link_title = linked_doc.name + def validate_reference(self): if self.is_your_company_address: if not [row for row in self.links if row.link_doctype == "Company"]: diff --git a/frappe/contacts/doctype/contact/contact.py b/frappe/contacts/doctype/contact/contact.py index 987fad3829..585c37a3db 100644 --- a/frappe/contacts/doctype/contact/contact.py +++ b/frappe/contacts/doctype/contact/contact.py @@ -31,6 +31,7 @@ class Contact(Document): if self.email_id: self.email_id = self.email_id.strip() self.set_user() + self.set_link_title() if self.email_id and not self.image: self.image = has_gravatar(self.email_id) @@ -40,6 +41,18 @@ class Contact(Document): if not self.user and self.email_id: self.user = frappe.db.get_value("User", {"email": self.email_id}) + def set_link_title(self): + if not self.links: + return + else: + for contact in self.links: + if not contact.link_title: + linked_doc = frappe.get_doc(contact.link_doctype, contact.link_name) + try: + contact.link_title = linked_doc.title_field + except AttributeError: + contact.link_title = linked_doc.name + def get_link_for(self, link_doctype): '''Return the link name, if exists for the given link DocType''' for link in self.links: From cf7f86f6ccc23b0e40225bf948a9222b24e41aaf Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Tue, 7 May 2019 15:22:12 +0530 Subject: [PATCH 02/12] chore: code improvements --- frappe/contacts/doctype/address/address.py | 12 ++++-------- frappe/contacts/doctype/contact/contact.py | 12 ++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/frappe/contacts/doctype/address/address.py b/frappe/contacts/doctype/address/address.py index 31f7ae766a..583643ad27 100644 --- a/frappe/contacts/doctype/address/address.py +++ b/frappe/contacts/doctype/address/address.py @@ -57,14 +57,10 @@ class Address(Document): def set_link_title(self): if not self.links: return - else: - for address in self.links: - if not address.link_title: - linked_doc = frappe.get_doc(address.link_doctype, address.link_name) - try: - address.link_title = linked_doc.title_field - except AttributeError: - address.link_title = linked_doc.name + for address in self.links: + if not address.link_title: + linked_doc = frappe.get_doc(address.link_doctype, address.link_name) + address.link_title = linked_doc.get("title_field") or linked_doc.get("name") def validate_reference(self): if self.is_your_company_address: diff --git a/frappe/contacts/doctype/contact/contact.py b/frappe/contacts/doctype/contact/contact.py index 585c37a3db..28f150f0d4 100644 --- a/frappe/contacts/doctype/contact/contact.py +++ b/frappe/contacts/doctype/contact/contact.py @@ -44,14 +44,10 @@ class Contact(Document): def set_link_title(self): if not self.links: return - else: - for contact in self.links: - if not contact.link_title: - linked_doc = frappe.get_doc(contact.link_doctype, contact.link_name) - try: - contact.link_title = linked_doc.title_field - except AttributeError: - contact.link_title = linked_doc.name + for contact in self.links: + if not contact.link_title: + linked_doc = frappe.get_doc(contact.link_doctype, contact.link_name) + contact.link_title = linked_doc.get("title_field") or linked_doc.get("name") def get_link_for(self, link_doctype): '''Return the link name, if exists for the given link DocType''' From 41fa47af62da0c6da4a827a7713fd783428849f7 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Tue, 14 May 2019 16:08:01 +0530 Subject: [PATCH 03/12] style: moved set_link_title to address_and_contact --- frappe/contacts/address_and_contact.py | 8 ++++++++ frappe/contacts/doctype/address/address.py | 11 ++--------- frappe/contacts/doctype/contact/contact.py | 11 ++--------- 3 files changed, 12 insertions(+), 18 deletions(-) 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 583643ad27..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,7 +40,7 @@ class Address(Document): def validate(self): self.link_address() self.validate_reference() - self.set_link_title() + set_link_title(self) deduplicate_dynamic_links(self) def link_address(self): @@ -54,14 +55,6 @@ class Address(Document): return False - def set_link_title(self): - if not self.links: - return - for address in self.links: - if not address.link_title: - linked_doc = frappe.get_doc(address.link_doctype, address.link_name) - address.link_title = linked_doc.get("title_field") or linked_doc.get("name") - def validate_reference(self): if self.is_your_company_address: if not [row for row in self.links if row.link_doctype == "Company"]: diff --git a/frappe/contacts/doctype/contact/contact.py b/frappe/contacts/doctype/contact/contact.py index 28f150f0d4..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,7 +32,7 @@ class Contact(Document): if self.email_id: self.email_id = self.email_id.strip() self.set_user() - self.set_link_title() + set_link_title(self) if self.email_id and not self.image: self.image = has_gravatar(self.email_id) @@ -41,14 +42,6 @@ class Contact(Document): if not self.user and self.email_id: self.user = frappe.db.get_value("User", {"email": self.email_id}) - def set_link_title(self): - if not self.links: - return - for contact in self.links: - if not contact.link_title: - linked_doc = frappe.get_doc(contact.link_doctype, contact.link_name) - contact.link_title = linked_doc.get("title_field") or linked_doc.get("name") - def get_link_for(self, link_doctype): '''Return the link name, if exists for the given link DocType''' for link in self.links: From 90f62016f8f5360fbf3420cff3097aaa7b2894c2 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 14 May 2019 16:19:45 +0530 Subject: [PATCH 04/12] fix: Clear DuplicateEntry message in setup --- frappe/desk/page/setup_wizard/setup_wizard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From f2068db6dd8230abd2842f1c1c616431567ea021 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 14 May 2019 16:20:06 +0530 Subject: [PATCH 05/12] fix: Limit one notification request at a time --- frappe/public/js/frappe/desk.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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) { From 6f5ad343c95c5e4da8c918536551bb2215d1c6f6 Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Tue, 14 May 2019 18:40:34 +0530 Subject: [PATCH 06/12] fix: filters for sending hourly updates in document follow (#7481) --- frappe/desk/form/document_follow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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] ] From a831abefdab2e530787ae70f3d974bba183f04ff Mon Sep 17 00:00:00 2001 From: Sahil Khan Date: Tue, 14 May 2019 18:56:24 +0530 Subject: [PATCH 07/12] fix(patch): reload dynamic link doctype --- frappe/patches/v11_0/create_contact_for_user.py | 1 + 1 file changed, 1 insertion(+) 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: From a0b1ae732f66dc8f574783a8c0b9f31956ae3bc7 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 15 May 2019 11:39:31 +0530 Subject: [PATCH 08/12] fix: Add currency code for Surinamese dollar --- frappe/geo/country_info.json | 1 + 1 file changed, 1 insertion(+) 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": "$", From 1bcdc0b7cb2cf110b2e3fad7f1e8c712866817b0 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 15 May 2019 11:59:13 +0530 Subject: [PATCH 09/12] fix(report): Allow report export only if user has export permission on ref doctype (#7458) * fix: Allow export only if user has export permission on reference doctype * fix: Show only custom "no permission" error * fix: while saving employee user getting user permissions error --- frappe/desk/query_report.py | 4 ++++ frappe/model/rename_doc.py | 2 +- frappe/permissions.py | 6 ++++-- frappe/public/js/frappe/views/reports/query_report.js | 1 + 4 files changed, 10 insertions(+), 3 deletions(-) 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/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/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/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 485f26f952..7baff2a25e 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 }, { From 25b190bb9cde3ee7d41b16b268d5d1296346dc08 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 15 May 2019 13:48:21 +0530 Subject: [PATCH 10/12] fix: permission fix for prepared report --- frappe/core/doctype/prepared_report/prepared_report.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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', From f01f36b6e583c2ce2cf43b0c0d2c5219c92f7ae4 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Wed, 15 May 2019 15:41:50 +0530 Subject: [PATCH 11/12] fix: Don't show no value type fields in options for custom columns (#7497) * fix: Don't show no value type fields in options for custom columns * fix: Use filter instead of pushing in list --- frappe/public/js/frappe/views/reports/query_report.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 7baff2a25e..5e7e79312f 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -992,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); }); } From 1a787984f496cd114ea31c8065af647120c2866c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 16 May 2019 10:16:06 +0530 Subject: [PATCH 12/12] fix: get month diff between 2 dates (#7474) (#7500) --- frappe/utils/data.py | 5 +++++ 1 file changed, 5 insertions(+) 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)