From 6cdf514fcbf6d8abd6663da63fc62ffafc10109d Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Mon, 26 Apr 2021 14:30:17 +0530 Subject: [PATCH 01/24] fix: auto repeat schedule not rendered in the dashboard --- frappe/automation/doctype/auto_repeat/auto_repeat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/automation/doctype/auto_repeat/auto_repeat.js b/frappe/automation/doctype/auto_repeat/auto_repeat.js index 7028ac486d..896a10dfe0 100644 --- a/frappe/automation/doctype/auto_repeat/auto_repeat.js +++ b/frappe/automation/doctype/auto_repeat/auto_repeat.js @@ -103,7 +103,7 @@ frappe.ui.form.on('Auto Repeat', { frappe.auto_repeat.render_schedule = function(frm) { if (!frm.is_dirty() && frm.doc.status !== 'Disabled') { frm.call("get_auto_repeat_schedule").then(r => { - frm.dashboard.wrapper.empty(); + frm.dashboard.reset(); frm.dashboard.add_section( frappe.render_template("auto_repeat_schedule", { schedule_details: r.message || [] From 483cd85eba617624da4fd60c8b3d2a1181ce4ea3 Mon Sep 17 00:00:00 2001 From: shariquerik Date: Thu, 6 May 2021 16:44:18 +0530 Subject: [PATCH 02/24] fix: Revert naming for custom naming series --- frappe/model/naming.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frappe/model/naming.py b/frappe/model/naming.py index 1a3f90da37..1cfcd56350 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -202,7 +202,12 @@ def revert_series_if_last(key, name, doc=None): if ".#" in key: prefix, hashes = key.rsplit(".", 1) if "#" not in hashes: - return + key = key.rsplit(".") + hash = list(filter(re.compile(".*#").match, key))[0] + if not hash: + return + name = name.replace(hashes, "") + prefix, hashes = key[:key.index(hash)+1] else: prefix = key From 9aa2f366dd6f51adde6fbd9be4fbc2b5c7a85ab9 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Wed, 20 Jan 2021 13:52:05 +0530 Subject: [PATCH 03/24] fix: Don't execute dynamic properties to check if conflicts exist --- frappe/core/doctype/doctype/doctype.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index 3588cc553a..6f33221155 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -1176,9 +1176,15 @@ def make_module_and_roles(doc, perm_fieldname="permissions"): def check_if_fieldname_conflicts_with_methods(doctype, fieldname): doc = frappe.get_doc({"doctype": doctype}) - method_list = [method for method in dir(doc) if isinstance(method, str) and callable(getattr(doc, method))] - - if fieldname in method_list: + available_objects = [x for x in dir(doc) if isinstance(x, str)] + property_list = [ + x for x in available_objects if isinstance(getattr(type(doc), x, None), property) + ] + method_list = [ + x for x in available_objects if x not in property_list and callable(getattr(doc, x)) + ] + + if fieldname in method_list + property_list: frappe.throw(_("Fieldname {0} conflicting with meta object").format(fieldname)) def clear_linked_doctype_cache(): From 255a959a3eb706ab25845aa94890708c37fe7573 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 4 Jan 2021 10:41:18 +0530 Subject: [PATCH 04/24] chore: Rename function to validate conflicting methods and properties --- frappe/core/doctype/doctype/doctype.py | 2 +- frappe/custom/doctype/custom_field/custom_field.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index 6f33221155..d277a217d1 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -1174,7 +1174,7 @@ def make_module_and_roles(doc, perm_fieldname="permissions"): else: raise -def check_if_fieldname_conflicts_with_methods(doctype, fieldname): +def check_if_fieldname_conflicts_with_properties_and_methods(doctype, fieldname): doc = frappe.get_doc({"doctype": doctype}) available_objects = [x for x in dir(doc) if isinstance(x, str)] property_list = [ diff --git a/frappe/custom/doctype/custom_field/custom_field.py b/frappe/custom/doctype/custom_field/custom_field.py index 3126326636..ac1213c727 100644 --- a/frappe/custom/doctype/custom_field/custom_field.py +++ b/frappe/custom/doctype/custom_field/custom_field.py @@ -64,8 +64,8 @@ class CustomField(Document): self.translatable = 0 if not self.flags.ignore_validate: - from frappe.core.doctype.doctype.doctype import check_if_fieldname_conflicts_with_methods - check_if_fieldname_conflicts_with_methods(self.dt, self.fieldname) + from frappe.core.doctype.doctype.doctype import check_if_fieldname_conflicts_with_properties_and_methods + check_if_fieldname_conflicts_with_properties_and_methods(self.dt, self.fieldname) def on_update(self): frappe.clear_cache(doctype=self.dt) From c652c7b7f52ad8d9a5b00b84af3f1ab33c3d1769 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 6 May 2021 11:58:17 +0530 Subject: [PATCH 05/24] feat: Validate field name conflicts in DocType.validate # Conflicts: # frappe/core/doctype/doctype/doctype.py --- frappe/core/doctype/doctype/doctype.py | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index d277a217d1..13ebcd82ac 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -70,6 +70,7 @@ class DocType(Document): validate_series(self) self.validate_document_type() validate_fields(self) + self.validate_field_name_conflicts() if not self.istable: validate_permissions(self) @@ -89,6 +90,39 @@ class DocType(Document): if self.default_print_format and not self.custom: frappe.throw(_('Standard DocType cannot have default print format, use Customize Form')) + if frappe.conf.get('developer_mode'): + self.owner = 'Administrator' + self.modified_by = 'Administrator' + + def validate_field_name_conflicts(self): + """Check if field names dont conflict with controller properties and methods""" + from frappe.model.base_document import get_controller + + controller = get_controller(self.name) + available_objects = {x for x in dir(controller) if isinstance(x, str)} + property_set = { + x for x in available_objects if isinstance(getattr(controller, x, None), property) + } + method_set = { + x for x in available_objects if x not in property_set and callable(getattr(controller, x, None)) + } + + for docfield in self.get("fields") or []: + conflict_type = "" + field = docfield.fieldname + field_label = docfield.label or docfield.fieldname + + if docfield.fieldname in method_set: + conflict_type = "controller method" + if docfield.fieldname in property_set: + conflict_type = "class property" + + if conflict_type: + frappe.throw( + _("Fieldname '{0}' conflicting with a {1} of the name {2} in {3}") + .format(field_label, conflict_type, field, self.name) + ) + def after_insert(self): # clear user cache so that on the next reload this doctype is included in boot clear_user_cache(frappe.session.user) From 78e1297392706eaa209e53d3acb42faae66dfa65 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 22 Jan 2021 18:08:18 +0530 Subject: [PATCH 06/24] chore: Drop dead file --- frappe/email/doctype/newsletter/newsletter..json | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 frappe/email/doctype/newsletter/newsletter..json diff --git a/frappe/email/doctype/newsletter/newsletter..json b/frappe/email/doctype/newsletter/newsletter..json deleted file mode 100644 index e69de29bb2..0000000000 From ce4253c6318546a7249f0edd518ad1f499f8fd88 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 25 Jan 2021 13:55:10 +0530 Subject: [PATCH 07/24] fix: Ignore 'special' DocTypes to avoid breaking changes eg: Fieldname 'Delete' conflicting with a controller method of the name delete in Custom DocPerm Fieldname 'Delete' conflicting with a controller method of the name delete in DocPerm Fieldname 'Precision' conflicting with a controller method of the name precision in Custom Field Fieldname 'Precision' conflicting with a controller method of the name precision in Customize Form Field Fieldname 'Precision' conflicting with a controller method of the name precision in DocField --- frappe/core/doctype/doctype/doctype.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index 13ebcd82ac..c1a8527512 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -96,6 +96,17 @@ class DocType(Document): def validate_field_name_conflicts(self): """Check if field names dont conflict with controller properties and methods""" + core_doctypes = [ + "Custom DocPerm", + "DocPerm", + "Custom Field", + "Customize Form Field", + "DocField", + ] + + if self.name in core_doctypes: + return + from frappe.model.base_document import get_controller controller = get_controller(self.name) From a3b79081d64e754d73fad46f26aa24ac42a32a2e Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Sat, 18 Jan 2020 04:11:19 +0530 Subject: [PATCH 08/24] fix: Use Document in case get_controller raises import errors --- frappe/core/doctype/doctype/doctype.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index c1a8527512..d361bb8a98 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -109,7 +109,11 @@ class DocType(Document): from frappe.model.base_document import get_controller - controller = get_controller(self.name) + try: + controller = get_controller(self.name) + except ImportError: + controller = Document + available_objects = {x for x in dir(controller) if isinstance(x, str)} property_set = { x for x in available_objects if isinstance(getattr(controller, x, None), property) From 05712abc60721f4633d6b0166648743154b56cca Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 18 Feb 2021 19:55:12 +0530 Subject: [PATCH 09/24] fix: Check for db value if cache doesn't exist in get_controller, if cached value doesn't exist for a DocType in the frappe.db.value_cache, then query the db as fallback before the final fallback of assuming module as Core and non custom --- frappe/model/base_document.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 05435482bd..9288d621c9 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -34,8 +34,11 @@ def get_controller(doctype): from frappe.model.document import Document from frappe.utils.nestedset import NestedSet - module_name, custom = frappe.db.get_value("DocType", doctype, ("module", "custom"), cache=True) \ + module_name, custom = ( + frappe.db.get_value("DocType", doctype, ("module", "custom"), cache=True) + or frappe.db.get_value("DocType", doctype, ("module", "custom")) or ["Core", False] + ) if custom: if frappe.db.field_exists("DocType", "is_tree"): From 843c544117e7f661cc97cc78c33349833b12df21 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 16 Mar 2021 12:23:10 +0530 Subject: [PATCH 10/24] refactor: Rename function and add docstring Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- frappe/core/doctype/doctype/doctype.py | 4 +++- frappe/custom/doctype/custom_field/custom_field.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index d361bb8a98..2cdccda8e1 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -1223,7 +1223,9 @@ def make_module_and_roles(doc, perm_fieldname="permissions"): else: raise -def check_if_fieldname_conflicts_with_properties_and_methods(doctype, fieldname): +def check_fieldname_conflicts(doctype, fieldname): + """Checks if fieldname conflicts with methods or properties""" + doc = frappe.get_doc({"doctype": doctype}) available_objects = [x for x in dir(doc) if isinstance(x, str)] property_list = [ diff --git a/frappe/custom/doctype/custom_field/custom_field.py b/frappe/custom/doctype/custom_field/custom_field.py index ac1213c727..b3f61c707d 100644 --- a/frappe/custom/doctype/custom_field/custom_field.py +++ b/frappe/custom/doctype/custom_field/custom_field.py @@ -64,8 +64,8 @@ class CustomField(Document): self.translatable = 0 if not self.flags.ignore_validate: - from frappe.core.doctype.doctype.doctype import check_if_fieldname_conflicts_with_properties_and_methods - check_if_fieldname_conflicts_with_properties_and_methods(self.dt, self.fieldname) + from frappe.core.doctype.doctype.doctype import check_fieldname_conflicts + check_fieldname_conflicts(self.dt, self.fieldname) def on_update(self): frappe.clear_cache(doctype=self.dt) From 877f9d08df70a741aa493421a002651ef0098cbc Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 16 Mar 2021 16:28:38 +0530 Subject: [PATCH 11/24] fix: Use fallback values if doctype values unset --- frappe/model/base_document.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 9288d621c9..2724e320c4 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -34,11 +34,15 @@ def get_controller(doctype): from frappe.model.document import Document from frappe.utils.nestedset import NestedSet - module_name, custom = ( - frappe.db.get_value("DocType", doctype, ("module", "custom"), cache=True) - or frappe.db.get_value("DocType", doctype, ("module", "custom")) - or ["Core", False] - ) + if frappe.flags.in_migrate or frappe.flags.in_install or frappe.flags.in_patch: + module_name, custom = ["Core", False] + else: + # this could be simplified in PY3.8 using walrus operators + result = frappe.db.get_value("DocType", doctype, ("module", "custom"), cache=True) + if result: + module_name, custom = result + else: + module_name, custom = ["Core", bool(not frappe.db.exists(doctype))] if custom: if frappe.db.field_exists("DocType", "is_tree"): From 87ed7796ded4053d8c1f04924716b29bc4848a6d Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 23 Apr 2021 12:43:13 +0530 Subject: [PATCH 12/24] fix: Use older logic to set module_name and custom vars --- frappe/model/base_document.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 2724e320c4..154a091b8a 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -34,15 +34,9 @@ def get_controller(doctype): from frappe.model.document import Document from frappe.utils.nestedset import NestedSet - if frappe.flags.in_migrate or frappe.flags.in_install or frappe.flags.in_patch: - module_name, custom = ["Core", False] - else: - # this could be simplified in PY3.8 using walrus operators - result = frappe.db.get_value("DocType", doctype, ("module", "custom"), cache=True) - if result: - module_name, custom = result - else: - module_name, custom = ["Core", bool(not frappe.db.exists(doctype))] + module_name, custom = frappe.db.get_value( + "DocType", doctype, ("module", "custom"), cache=True + ) or ["Core", False] if custom: if frappe.db.field_exists("DocType", "is_tree"): From bc08459ca77194bc5853a21b311aebfd125d62e9 Mon Sep 17 00:00:00 2001 From: shariquerik Date: Thu, 6 May 2021 17:22:59 +0530 Subject: [PATCH 13/24] test: Test case for revert series --- frappe/tests/test_naming.py | 98 +++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 38 deletions(-) diff --git a/frappe/tests/test_naming.py b/frappe/tests/test_naming.py index b47fb809ca..fbfb1e677d 100644 --- a/frappe/tests/test_naming.py +++ b/frappe/tests/test_naming.py @@ -16,50 +16,50 @@ class TestNaming(unittest.TestCase): todo_doctype.autoname = 'hash' todo_doctype.save() - def test_append_number_if_name_exists(self): - ''' - Append number to name based on existing values - if Bottle exists - Bottle -> Bottle-1 - if Bottle-1 exists - Bottle -> Bottle-2 - ''' - - note = frappe.new_doc('Note') - note.title = 'Test' - note.insert() - - title2 = append_number_if_name_exists('Note', 'Test') - self.assertEqual(title2, 'Test-1') - - title2 = append_number_if_name_exists('Note', 'Test', 'title', '_') - self.assertEqual(title2, 'Test_1') - - def test_format_autoname(self): - ''' - Test if braced params are replaced in format autoname - ''' - doctype = 'ToDo' - - todo_doctype = frappe.get_doc('DocType', doctype) - todo_doctype.autoname = 'format:TODO-{MM}-{status}-{##}' - todo_doctype.save() + # def test_append_number_if_name_exists(self): + # ''' + # Append number to name based on existing values + # if Bottle exists + # Bottle -> Bottle-1 + # if Bottle-1 exists + # Bottle -> Bottle-2 + # ''' + + # note = frappe.new_doc('Note') + # note.title = 'Test' + # note.insert() + + # title2 = append_number_if_name_exists('Note', 'Test') + # self.assertEqual(title2, 'Test-1') + + # title2 = append_number_if_name_exists('Note', 'Test', 'title', '_') + # self.assertEqual(title2, 'Test_1') + + # def test_format_autoname(self): + # ''' + # Test if braced params are replaced in format autoname + # ''' + # doctype = 'ToDo' + + # todo_doctype = frappe.get_doc('DocType', doctype) + # todo_doctype.autoname = 'format:TODO-{MM}-{status}-{##}' + # todo_doctype.save() - description = 'Format' + # description = 'Format' - todo = frappe.new_doc(doctype) - todo.description = description - todo.insert() + # todo = frappe.new_doc(doctype) + # todo.description = description + # todo.insert() - series = getseries('', 2) + # series = getseries('', 2) - series = str(int(series)-1) + # series = str(int(series)-1) - if len(series) < 2: - series = '0' + series + # if len(series) < 2: + # series = '0' + series - self.assertEqual(todo.name, 'TODO-{month}-{status}-{series}'.format( - month=now_datetime().strftime('%m'), status=todo.status, series=series)) + # self.assertEqual(todo.name, 'TODO-{month}-{status}-{series}'.format( + # month=now_datetime().strftime('%m'), status=todo.status, series=series)) def test_revert_series(self): from datetime import datetime @@ -95,3 +95,25 @@ class TestNaming(unittest.TestCase): self.assertEqual(count.get('current'), 2) frappe.db.sql("""delete from `tabSeries` where name = %s""", series) + + series = 'TEST1-' + key = 'TEST1-.#####.-2021-22' + name = 'TEST1-00003-2021-22' + frappe.db.sql("DELETE FROM `tabSeries` WHERE `name`=%s", series) + frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 3)""", (series,)) + revert_series_if_last(key, name) + count = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] + + self.assertEqual(count.get('current'), 2) + frappe.db.sql("""delete from `tabSeries` where name = %s""", series) + + series = '' + key = '.#####.-2021-22' + name = '00003-2021-22' + frappe.db.sql("DELETE FROM `tabSeries` WHERE `name`=%s", series) + frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 3)""", (series,)) + revert_series_if_last(key, name) + count = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] + + self.assertEqual(count.get('current'), 2) + frappe.db.sql("""delete from `tabSeries` where name = %s""", series) From 47d1f3d50abff0d253c157e760a72ad1eff3b696 Mon Sep 17 00:00:00 2001 From: shariquerik Date: Thu, 6 May 2021 17:24:12 +0530 Subject: [PATCH 14/24] test: uncomment --- frappe/tests/test_naming.py | 76 ++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/frappe/tests/test_naming.py b/frappe/tests/test_naming.py index fbfb1e677d..0c3481ba98 100644 --- a/frappe/tests/test_naming.py +++ b/frappe/tests/test_naming.py @@ -16,50 +16,50 @@ class TestNaming(unittest.TestCase): todo_doctype.autoname = 'hash' todo_doctype.save() - # def test_append_number_if_name_exists(self): - # ''' - # Append number to name based on existing values - # if Bottle exists - # Bottle -> Bottle-1 - # if Bottle-1 exists - # Bottle -> Bottle-2 - # ''' - - # note = frappe.new_doc('Note') - # note.title = 'Test' - # note.insert() - - # title2 = append_number_if_name_exists('Note', 'Test') - # self.assertEqual(title2, 'Test-1') - - # title2 = append_number_if_name_exists('Note', 'Test', 'title', '_') - # self.assertEqual(title2, 'Test_1') - - # def test_format_autoname(self): - # ''' - # Test if braced params are replaced in format autoname - # ''' - # doctype = 'ToDo' - - # todo_doctype = frappe.get_doc('DocType', doctype) - # todo_doctype.autoname = 'format:TODO-{MM}-{status}-{##}' - # todo_doctype.save() + def test_append_number_if_name_exists(self): + ''' + Append number to name based on existing values + if Bottle exists + Bottle -> Bottle-1 + if Bottle-1 exists + Bottle -> Bottle-2 + ''' + + note = frappe.new_doc('Note') + note.title = 'Test' + note.insert() + + title2 = append_number_if_name_exists('Note', 'Test') + self.assertEqual(title2, 'Test-1') + + title2 = append_number_if_name_exists('Note', 'Test', 'title', '_') + self.assertEqual(title2, 'Test_1') + + def test_format_autoname(self): + ''' + Test if braced params are replaced in format autoname + ''' + doctype = 'ToDo' + + todo_doctype = frappe.get_doc('DocType', doctype) + todo_doctype.autoname = 'format:TODO-{MM}-{status}-{##}' + todo_doctype.save() - # description = 'Format' + description = 'Format' - # todo = frappe.new_doc(doctype) - # todo.description = description - # todo.insert() + todo = frappe.new_doc(doctype) + todo.description = description + todo.insert() - # series = getseries('', 2) + series = getseries('', 2) - # series = str(int(series)-1) + series = str(int(series)-1) - # if len(series) < 2: - # series = '0' + series + if len(series) < 2: + series = '0' + series - # self.assertEqual(todo.name, 'TODO-{month}-{status}-{series}'.format( - # month=now_datetime().strftime('%m'), status=todo.status, series=series)) + self.assertEqual(todo.name, 'TODO-{month}-{status}-{series}'.format( + month=now_datetime().strftime('%m'), status=todo.status, series=series)) def test_revert_series(self): from datetime import datetime From f46c3b59a6385f3d470b03712e00ce0ad5cf289c Mon Sep 17 00:00:00 2001 From: shariquerik Date: Thu, 6 May 2021 17:26:54 +0530 Subject: [PATCH 15/24] fix: sider fix --- frappe/tests/test_naming.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/tests/test_naming.py b/frappe/tests/test_naming.py index 0c3481ba98..f808d06db3 100644 --- a/frappe/tests/test_naming.py +++ b/frappe/tests/test_naming.py @@ -106,7 +106,7 @@ class TestNaming(unittest.TestCase): self.assertEqual(count.get('current'), 2) frappe.db.sql("""delete from `tabSeries` where name = %s""", series) - + series = '' key = '.#####.-2021-22' name = '00003-2021-22' From 926d13e69ef88309f409446d2dc1c2e3f65ab0f3 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 7 May 2021 18:02:25 +0530 Subject: [PATCH 16/24] fix: Skip field-method conflicts validation on new docs --- frappe/core/doctype/doctype/doctype.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index 2cdccda8e1..e0b9d15114 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -70,7 +70,6 @@ class DocType(Document): validate_series(self) self.validate_document_type() validate_fields(self) - self.validate_field_name_conflicts() if not self.istable: validate_permissions(self) @@ -84,6 +83,7 @@ class DocType(Document): if not self.is_new(): self.before_update = frappe.get_doc('DocType', self.name) self.setup_fields_to_fetch() + self.validate_field_name_conflicts() check_email_append_to(self) From e7552413b4212e1daf47660b72838d1713c6a9bd Mon Sep 17 00:00:00 2001 From: shariquerik Date: Fri, 7 May 2021 18:10:59 +0530 Subject: [PATCH 17/24] refactor: minor fix --- frappe/model/naming.py | 1 + frappe/tests/test_naming.py | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/frappe/model/naming.py b/frappe/model/naming.py index 1cfcd56350..dbe77562d0 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -203,6 +203,7 @@ def revert_series_if_last(key, name, doc=None): prefix, hashes = key.rsplit(".", 1) if "#" not in hashes: key = key.rsplit(".") + # get the hash part from the key hash = list(filter(re.compile(".*#").match, key))[0] if not hash: return diff --git a/frappe/tests/test_naming.py b/frappe/tests/test_naming.py index f808d06db3..66d48e3612 100644 --- a/frappe/tests/test_naming.py +++ b/frappe/tests/test_naming.py @@ -70,9 +70,9 @@ class TestNaming(unittest.TestCase): name = 'TEST-{}-00001'.format(year) frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 1)""", (series,)) revert_series_if_last(key, name) - count = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] + current_index = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] - self.assertEqual(count.get('current'), 0) + self.assertEqual(current_index.get('current'), 0) frappe.db.sql("""delete from `tabSeries` where name = %s""", series) series = 'TEST-{}-'.format(year) @@ -80,9 +80,9 @@ class TestNaming(unittest.TestCase): name = 'TEST-{}-00002'.format(year) frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 2)""", (series,)) revert_series_if_last(key, name) - count = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] + current_index = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] - self.assertEqual(count.get('current'), 1) + self.assertEqual(current_index.get('current'), 1) frappe.db.sql("""delete from `tabSeries` where name = %s""", series) series = 'TEST-' @@ -91,9 +91,9 @@ class TestNaming(unittest.TestCase): frappe.db.sql("DELETE FROM `tabSeries` WHERE `name`=%s", series) frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 3)""", (series,)) revert_series_if_last(key, name) - count = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] + current_index = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] - self.assertEqual(count.get('current'), 2) + self.assertEqual(current_index.get('current'), 2) frappe.db.sql("""delete from `tabSeries` where name = %s""", series) series = 'TEST1-' @@ -102,9 +102,9 @@ class TestNaming(unittest.TestCase): frappe.db.sql("DELETE FROM `tabSeries` WHERE `name`=%s", series) frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 3)""", (series,)) revert_series_if_last(key, name) - count = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] + current_index = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] - self.assertEqual(count.get('current'), 2) + self.assertEqual(current_index.get('current'), 2) frappe.db.sql("""delete from `tabSeries` where name = %s""", series) series = '' @@ -113,7 +113,7 @@ class TestNaming(unittest.TestCase): frappe.db.sql("DELETE FROM `tabSeries` WHERE `name`=%s", series) frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 3)""", (series,)) revert_series_if_last(key, name) - count = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] + current_index = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] - self.assertEqual(count.get('current'), 2) + self.assertEqual(current_index.get('current'), 2) frappe.db.sql("""delete from `tabSeries` where name = %s""", series) From c84feb16e9e456cdd040f20a6ac154d3a1d760c0 Mon Sep 17 00:00:00 2001 From: gavin Date: Sat, 8 May 2021 12:39:27 +0530 Subject: [PATCH 18/24] fix: Avoid possible whitespace bug * Handles semgrep warning * Changed "" to None as a precaution against future whitespace bugs via human error Co-authored-by: Ankush Menat --- frappe/core/doctype/doctype/doctype.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index e0b9d15114..6eef5a4023 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -123,7 +123,7 @@ class DocType(Document): } for docfield in self.get("fields") or []: - conflict_type = "" + conflict_type = None field = docfield.fieldname field_label = docfield.label or docfield.fieldname From bf33a80042cc76e2cbc36991330d7dbbd7a33db4 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Mon, 3 May 2021 17:14:45 +0530 Subject: [PATCH 19/24] fix(setup): do not show messsage when exception is handled (cherry picked from commit ac9fe71733af5fe944cbca62dd688d2e49254497) --- frappe/translate.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frappe/translate.py b/frappe/translate.py index 4baf4bdd89..5c5480d0a2 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -540,8 +540,12 @@ def extract_messages_from_code(code): try: code = frappe.as_unicode(render_include(code)) - except (TemplateError, ImportError, InvalidIncludePath, IOError): - # Exception will occur when it encounters John Resig's microtemplating code + + # Exception will occur when it encounters John Resig's microtemplating code + except (TemplateError, ImportError, InvalidIncludePath, IOError) as e: + if isinstance(e, InvalidIncludePath): + frappe.clear_last_message() + pass messages = [] From 0bbf7c89bfdb8919c93b9da48ba45ee36bf81177 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 8 May 2021 17:38:38 +0550 Subject: [PATCH 20/24] bumped to version 13.2.2 --- frappe/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 12346d78c3..1a495d8ce1 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -34,7 +34,7 @@ if PY2: reload(sys) sys.setdefaultencoding("utf-8") -__version__ = '13.2.1' +__version__ = '13.2.2' __title__ = "Frappe Framework" From 8995e8e9db83b40e9df19433b77ec7ee853eaf18 Mon Sep 17 00:00:00 2001 From: shariquerik Date: Sun, 9 May 2021 06:24:20 +0530 Subject: [PATCH 21/24] refactor: remove unnecessary code --- frappe/model/naming.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/model/naming.py b/frappe/model/naming.py index dbe77562d0..ade4eaad95 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -202,13 +202,13 @@ def revert_series_if_last(key, name, doc=None): if ".#" in key: prefix, hashes = key.rsplit(".", 1) if "#" not in hashes: - key = key.rsplit(".") + key = key.split(".") # get the hash part from the key hash = list(filter(re.compile(".*#").match, key))[0] if not hash: return name = name.replace(hashes, "") - prefix, hashes = key[:key.index(hash)+1] + prefix = prefix.replace(".{}".format(hash), "") else: prefix = key From 36d6d224df87e03e6247afc4ec873fb8058ba000 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 10 May 2021 12:18:37 +0530 Subject: [PATCH 22/24] fix: Do not skip text in save while using shortcut --- frappe/public/js/frappe/desk.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index 6bcd20c494..d6cb7f5507 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -474,14 +474,19 @@ frappe.Application = Class.extend({ $('').appendTo("head"); }, trigger_primary_action: function() { - if(window.cur_dialog && cur_dialog.display) { - // trigger primary - cur_dialog.get_primary_btn().trigger("click"); - } else if(cur_frm && cur_frm.page.btn_primary.is(':visible')) { - cur_frm.page.btn_primary.trigger('click'); - } else if(frappe.container.page.save_action) { - frappe.container.page.save_action(); - } + // to trigger change event on active input before triggering primary action + $(document.activeElement).blur(); + // wait for possible JS validations triggered after blur (it might change primary button) + setTimeout(() => { + if (window.cur_dialog && cur_dialog.display) { + // trigger primary + cur_dialog.get_primary_btn().trigger("click"); + } else if (cur_frm && cur_frm.page.btn_primary.is(':visible')) { + cur_frm.page.btn_primary.trigger('click'); + } else if (frappe.container.page.save_action) { + frappe.container.page.save_action(); + } + }, 100); }, set_rtl: function() { From e0efefd9e5756fb3e17fe2891964c9a6d0831607 Mon Sep 17 00:00:00 2001 From: shariquerik Date: Mon, 10 May 2021 12:54:04 +0530 Subject: [PATCH 23/24] refactor: Used re.search also added examples --- frappe/model/naming.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/frappe/model/naming.py b/frappe/model/naming.py index ade4eaad95..c5b2775ec5 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -199,16 +199,39 @@ def getseries(key, digits): def revert_series_if_last(key, name, doc=None): - if ".#" in key: + """ + Reverts the series for particular naming series: + * key is naming series - SINV-.YYYY-.#### + * name is actual name - SINV-2021-0001 + + 1. This function split the key into two parts prefix (SINV-YYYY) & hashes (####). + 2. Use prefix to get the current index of that naming series from Series table + 3. Then revert the current index. + + *For custom naming series:* + 1. hash can exist anywhere, if it exist in hashes then it take normal flow. + 2. If hash doesn't exit in hashes, we get the hash from prefix, then update name and prefix accordingly. + + *Example:* + 1. key = SINV-.YYYY.- + * If key doesn't have hash it will add hash at the end + * prefix will be SINV-YYYY based on this will get current index from Series table. + 2. key = SINV-.####.-2021 + * now prefix = SINV-#### and hashes = 2021 (hash doesn't exist) + * will search hash in key then accordingly get prefix = SINV- + 3. key = ####.-2021 + * prefix = #### and hashes = 2021 (hash doesn't exist) + * will search hash in key then accordingly get prefix = "" + """ + if ".#" in key: prefix, hashes = key.rsplit(".", 1) if "#" not in hashes: - key = key.split(".") # get the hash part from the key - hash = list(filter(re.compile(".*#").match, key))[0] + hash = re.search("#+", key) if not hash: return name = name.replace(hashes, "") - prefix = prefix.replace(".{}".format(hash), "") + prefix = prefix.replace(hash.group(), "") else: prefix = key From 9919ddff2a937555881f43b83b22cd517555a94c Mon Sep 17 00:00:00 2001 From: shariquerik Date: Mon, 10 May 2021 12:56:15 +0530 Subject: [PATCH 24/24] fix: sider fix --- frappe/model/naming.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/naming.py b/frappe/model/naming.py index c5b2775ec5..359b8e2367 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -214,7 +214,7 @@ def revert_series_if_last(key, name, doc=None): *Example:* 1. key = SINV-.YYYY.- - * If key doesn't have hash it will add hash at the end + * If key doesn't have hash it will add hash at the end * prefix will be SINV-YYYY based on this will get current index from Series table. 2. key = SINV-.####.-2021 * now prefix = SINV-#### and hashes = 2021 (hash doesn't exist)