From 1c4e1bc1df7e0788e235b4f735194d8567de6e58 Mon Sep 17 00:00:00 2001 From: prssanna Date: Wed, 14 Apr 2021 14:48:15 +0530 Subject: [PATCH 01/33] refactor: set amended docname to original docname --- frappe/core/doctype/doctype/doctype.py | 16 ++++++ frappe/model/document.py | 10 +++- frappe/model/naming.py | 53 +++++++++++++++++-- frappe/patches.txt | 1 + ...l_name_docfield_to_submittable_doctypes.py | 11 ++++ frappe/public/js/frappe/form/form.js | 24 +++++---- frappe/public/js/frappe/router.js | 6 +++ 7 files changed, 105 insertions(+), 16 deletions(-) create mode 100644 frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index 84673f990a..3890ab3a32 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -74,6 +74,7 @@ class DocType(Document): if not self.istable: validate_permissions(self) + self.make_cancellable() self.make_amendable() self.make_repeatable() self.validate_nestedset() @@ -589,6 +590,21 @@ class DocType(Document): "no_copy": 1 }) + def make_cancellable(self): + """If is_submittable is set, add original_name docfield.""" + if self.is_submittable: + if not frappe.db.sql("""select name from tabDocField + where fieldname = 'original_name' and parent = %s""", self.name): + self.append("fields", { + "label": "Original Name", + "fieldtype": "Text", + "fieldname": "original_name", + "read_only": 1, + "hidden": 1, + "print_hide": 1, + "no_copy": 1 + }) + def make_repeatable(self): """If allow_auto_repeat is set, add auto_repeat custom field.""" if self.allow_auto_repeat: diff --git a/frappe/model/document.py b/frappe/model/document.py index 623916597e..2bb4f1f3c0 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -7,7 +7,7 @@ import time from frappe import _, msgprint, is_whitelisted from frappe.utils import flt, cstr, now, get_datetime_str, file_lock, date_diff from frappe.model.base_document import BaseDocument, get_controller -from frappe.model.naming import set_new_name +from frappe.model.naming import set_new_name, rename_cancelled_doc from six import iteritems, string_types from werkzeug.exceptions import NotFound, Forbidden import hashlib, json @@ -919,6 +919,14 @@ class Document(BaseDocument): @whitelist.__func__ def _cancel(self): """Cancel the document. Sets `docstatus` = 2, then saves.""" + + # for backward compatibility + if self.amended_from and not self.original_name: + self.original_name = None + else: + self.original_name = self.name + + self.name = rename_cancelled_doc(self) self.docstatus = 2 self.save() diff --git a/frappe/model/naming.py b/frappe/model/naming.py index b8d6a6f8d7..33a09c659a 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -223,7 +223,16 @@ def revert_series_if_last(key, name, doc=None): * prefix = #### and hashes = 2021 (hash doesn't exist) * will search hash in key then accordingly get prefix = "" """ - if ".#" in key: + + # do not revert if doc is amended, since cancelled docs still exist + if doc.docstatus != 2 and doc.amended_from: + return + + # for first cancelled doc + if doc.docstatus == 2 and not doc.amended_from and doc.original_name: + name = doc.original_name + + if ".#" in key: prefix, hashes = key.rsplit(".", 1) if "#" not in hashes: # get the hash part from the key @@ -306,14 +315,48 @@ def append_number_if_name_exists(doctype, value, fieldname="name", separator="-" def _set_amended_name(doc): + if doc.original_name: + doc.name = doc.original_name + else: + original_name = get_original_name(doc) + doc.name = doc.amended_from + + # rename original doc to next name in series, and set amended doc name as original name + next_name_in_series = get_new_name_from_amended_from(doc) + frappe.rename_doc(doc.doctype, original_name, next_name_in_series, force=True, show_alert=False) + doc.name = original_name + doc.amended_from = next_name_in_series + doc.original_name = original_name + + return doc.name + +def get_original_name(doc): + # get original doc name from chain of amended docs + amended_from = original_name = doc.amended_from + while amended_from: + original_name = amended_from + amended_from = frappe.db.get_value(doc.doctype, amended_from, "amended_from") + + return original_name + +def get_new_name_from_amended_from(doc): am_id = 1 - am_prefix = doc.amended_from - if frappe.db.get_value(doc.doctype, doc.amended_from, "amended_from"): + am_prefix = doc.name + if frappe.db.get_value(doc.doctype, doc.name, "amended_from"): am_id = cint(doc.amended_from.split("-")[-1]) + 1 am_prefix = "-".join(doc.amended_from.split("-")[:-1]) # except the last hyphen - doc.name = am_prefix + "-" + str(am_id) - return doc.name + new_name = am_prefix + "-" + str(am_id) + if new_name == doc.name: + am_id += 1 + new_name = am_prefix + "-" + str(am_id) + return new_name + +def rename_cancelled_doc(doc): + doc = frappe.parse_json(doc) + new_name = get_new_name_from_amended_from(doc) + frappe.rename_doc(doc.doctype, doc.name, new_name, force=True, show_alert=False) + return new_name def _field_autoname(autoname, doc, skip_slicing=None): diff --git a/frappe/patches.txt b/frappe/patches.txt index e70be0a37b..a722bb39fa 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -337,3 +337,4 @@ frappe.patches.v12_0.rename_uploaded_files_with_proper_name frappe.patches.v13_0.queryreport_columns frappe.patches.v13_0.jinja_hook frappe.patches.v13_0.update_notification_channel_if_empty +frappe.patches.v13_0.add_original_name_docfield_to_submittable_doctypes ####### diff --git a/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py b/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py new file mode 100644 index 0000000000..725d37fd4a --- /dev/null +++ b/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py @@ -0,0 +1,11 @@ +import frappe +from frappe.database.schema import add_column + +def execute(): + for doctype in frappe.db.get_all('DocType'): + doctype = frappe.get_doc("DocType", doctype.name) + if doctype.is_submittable and frappe.db.table_exists(doctype.name): + doctype.make_cancellable() + if not frappe.db.has_column(doctype.name, 'original_name'): + add_column(doctype.name, 'original_name', 'Text') + doctype.db_update_all() diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 6d8a6b1cb4..f9d9de967e 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -764,32 +764,36 @@ frappe.ui.form.Form = class FrappeForm { } _cancel(btn, callback, on_error, skip_confirm) { - const me = this; const cancel_doc = () => { frappe.validated = true; - me.script_manager.trigger("before_cancel").then(() => { + this.script_manager.trigger("before_cancel").then(() => { if (!frappe.validated) { - return me.handle_save_fail(btn, on_error); + return this.handle_save_fail(btn, on_error); } - var after_cancel = function(r) { + const original_name = this.docname; + const after_cancel = (r) => { if (r.exc) { - me.handle_save_fail(btn, on_error); + this.handle_save_fail(btn, on_error); } else { frappe.utils.play_sound("cancel"); - me.refresh(); callback && callback(); - me.script_manager.trigger("after_cancel"); + this.script_manager.trigger("after_cancel"); + frappe.run_serially([ + () => this.rename_notify(this.doctype, original_name, r.docs[0].name), + () => frappe.router.clear_re_route(this.doctype, original_name), + () => this.refresh(), + ]); } }; - frappe.ui.form.save(me, "cancel", after_cancel, btn); + frappe.ui.form.save(this, "cancel", after_cancel, btn); }); } if (skip_confirm) { cancel_doc(); } else { - frappe.confirm(__("Permanently Cancel {0}?", [this.docname]), cancel_doc, me.handle_save_fail(btn, on_error)); + frappe.confirm(__("Permanently Cancel {0}?", [this.docname]), cancel_doc, this.handle_save_fail(btn, on_error)); } }; @@ -811,7 +815,7 @@ frappe.ui.form.Form = class FrappeForm { 'docname': this.doc.name }).then(is_amended => { if (is_amended) { - frappe.throw(__('This document is already amended, you cannot ammend it again')); + frappe.throw(__('This document is already amended, you cannot amend it again')); } this.validate_form_action("Amend"); var me = this; diff --git a/frappe/public/js/frappe/router.js b/frappe/public/js/frappe/router.js index 5378294855..0d5231260c 100644 --- a/frappe/public/js/frappe/router.js +++ b/frappe/public/js/frappe/router.js @@ -235,6 +235,12 @@ frappe.router = { } }, + clear_re_route(doctype, docname) { + delete frappe.re_route[ + `${encodeURIComponent(frappe.router.slug(doctype))}/${encodeURIComponent(docname)}` + ]; + }, + set_title(sub_path) { if (frappe.route_titles[sub_path]) { frappe.utils.set_title(frappe.route_titles[sub_path]); From 251f878009f8f0e5574307ffd4275cd6ff36e3bc Mon Sep 17 00:00:00 2001 From: prssanna Date: Thu, 15 Apr 2021 11:20:16 +0530 Subject: [PATCH 02/33] test: test naming for cancelled and amended docs --- frappe/tests/test_naming.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/frappe/tests/test_naming.py b/frappe/tests/test_naming.py index 66d48e3612..765ead275f 100644 --- a/frappe/tests/test_naming.py +++ b/frappe/tests/test_naming.py @@ -117,3 +117,36 @@ class TestNaming(unittest.TestCase): self.assertEqual(current_index.get('current'), 2) frappe.db.sql("""delete from `tabSeries` where name = %s""", series) + + def test_naming_for_cancelled_and_amended_doc(self): + if not frappe.db.exists('DocType', 'Submittable Doctype'): + frappe.get_doc({ + "doctype": "DocType", + "module": "Core", + "custom": 1, + "is_submittable": 1, + "permissions": [{ + "role": "System Manager", + "read": 1 + }], + "name": 'Submittable Doctype' + }).insert() + + doc = frappe.new_doc('Submittable DocType') + doc.save() + original_name = doc.name + + doc.submit() + doc.cancel() + cancelled_name = doc.name + self.assertEqual(cancelled_name, "{}-1".format(original_name)) + + amended_doc = frappe.copy_doc(doc) + amended_doc.docstatus = 0 + amended_doc.amended_from = doc.name + amended_doc.save() + self.assertEqual(amended_doc.name, original_name) + + amended_doc.submit() + amended_doc.cancel() + self.assertEqual(amended_doc.name, "{}-2".format(original_name)) From 304a771ba2221aa15cb9f186799a0603cb5ee425 Mon Sep 17 00:00:00 2001 From: prssanna Date: Thu, 15 Apr 2021 11:21:48 +0530 Subject: [PATCH 03/33] fix: check if doc has attribute amended_from --- frappe/model/naming.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/frappe/model/naming.py b/frappe/model/naming.py index 33a09c659a..b685886c58 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -224,13 +224,14 @@ def revert_series_if_last(key, name, doc=None): * will search hash in key then accordingly get prefix = "" """ - # do not revert if doc is amended, since cancelled docs still exist - if doc.docstatus != 2 and doc.amended_from: - return + if hasattr(doc, 'amended_from'): + # do not revert if doc is amended, since cancelled docs still exist + if doc.docstatus != 2 and doc.amended_from: + return - # for first cancelled doc - if doc.docstatus == 2 and not doc.amended_from and doc.original_name: - name = doc.original_name + # for first cancelled doc + if doc.docstatus == 2 and not doc.amended_from and doc.original_name: + name = doc.original_name if ".#" in key: prefix, hashes = key.rsplit(".", 1) From 3614ca2a4d9ed0831cd3bd7080e977a5c2622149 Mon Sep 17 00:00:00 2001 From: prssanna Date: Thu, 15 Apr 2021 12:17:53 +0530 Subject: [PATCH 04/33] style: fix indent --- frappe/core/doctype/doctype/doctype.py | 18 +++++++++--------- frappe/tests/test_naming.py | 23 +++++++++++------------ 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index 3890ab3a32..0d478015bb 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -580,15 +580,15 @@ class DocType(Document): if self.is_submittable: if not frappe.db.sql("""select name from tabDocField where fieldname = 'amended_from' and parent = %s""", self.name): - self.append("fields", { - "label": "Amended From", - "fieldtype": "Link", - "fieldname": "amended_from", - "options": self.name, - "read_only": 1, - "print_hide": 1, - "no_copy": 1 - }) + self.append("fields", { + "label": "Amended From", + "fieldtype": "Link", + "fieldname": "amended_from", + "options": self.name, + "read_only": 1, + "print_hide": 1, + "no_copy": 1 + }) def make_cancellable(self): """If is_submittable is set, add original_name docfield.""" diff --git a/frappe/tests/test_naming.py b/frappe/tests/test_naming.py index 765ead275f..afaabcc805 100644 --- a/frappe/tests/test_naming.py +++ b/frappe/tests/test_naming.py @@ -119,18 +119,17 @@ class TestNaming(unittest.TestCase): frappe.db.sql("""delete from `tabSeries` where name = %s""", series) def test_naming_for_cancelled_and_amended_doc(self): - if not frappe.db.exists('DocType', 'Submittable Doctype'): - frappe.get_doc({ - "doctype": "DocType", - "module": "Core", - "custom": 1, - "is_submittable": 1, - "permissions": [{ - "role": "System Manager", - "read": 1 - }], - "name": 'Submittable Doctype' - }).insert() + frappe.get_doc({ + "doctype": "DocType", + "module": "Core", + "custom": 1, + "is_submittable": 1, + "permissions": [{ + "role": "System Manager", + "read": 1 + }], + "name": 'Submittable Doctype' + }).insert() doc = frappe.new_doc('Submittable DocType') doc.save() From ba267b6e628ea57009aa310645ba2f539708fe76 Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 16 Apr 2021 13:03:21 +0530 Subject: [PATCH 05/33] fix: update patch --- frappe/patches.txt | 2 +- .../add_original_name_docfield_to_submittable_doctypes.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/frappe/patches.txt b/frappe/patches.txt index a722bb39fa..1db775f17c 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -337,4 +337,4 @@ frappe.patches.v12_0.rename_uploaded_files_with_proper_name frappe.patches.v13_0.queryreport_columns frappe.patches.v13_0.jinja_hook frappe.patches.v13_0.update_notification_channel_if_empty -frappe.patches.v13_0.add_original_name_docfield_to_submittable_doctypes ####### +frappe.patches.v13_0.add_original_name_docfield_to_submittable_doctypes diff --git a/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py b/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py index 725d37fd4a..d870e63305 100644 --- a/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py +++ b/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py @@ -1,11 +1,9 @@ import frappe -from frappe.database.schema import add_column def execute(): for doctype in frappe.db.get_all('DocType'): doctype = frappe.get_doc("DocType", doctype.name) if doctype.is_submittable and frappe.db.table_exists(doctype.name): doctype.make_cancellable() - if not frappe.db.has_column(doctype.name, 'original_name'): - add_column(doctype.name, 'original_name', 'Text') + frappe.reload_doctype(doctype.name) doctype.db_update_all() From 26801f215cf03f9cb921752456ca6117bbb987f3 Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 16 Apr 2021 13:10:14 +0530 Subject: [PATCH 06/33] fix: use orm --- frappe/core/doctype/doctype/doctype.py | 48 +++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index 0d478015bb..aad0321fa0 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -577,33 +577,33 @@ class DocType(Document): def make_amendable(self): """If is_submittable is set, add amended_from docfields.""" - if self.is_submittable: - if not frappe.db.sql("""select name from tabDocField - where fieldname = 'amended_from' and parent = %s""", self.name): - self.append("fields", { - "label": "Amended From", - "fieldtype": "Link", - "fieldname": "amended_from", - "options": self.name, - "read_only": 1, - "print_hide": 1, - "no_copy": 1 - }) + if self.is_submittable and\ + not frappe.db.get_value('DocField', {'fieldname': 'amended_from', 'parent': self.name}): + + self.append("fields", { + "label": "Amended From", + "fieldtype": "Link", + "fieldname": "amended_from", + "options": self.name, + "read_only": 1, + "print_hide": 1, + "no_copy": 1 + }) def make_cancellable(self): """If is_submittable is set, add original_name docfield.""" - if self.is_submittable: - if not frappe.db.sql("""select name from tabDocField - where fieldname = 'original_name' and parent = %s""", self.name): - self.append("fields", { - "label": "Original Name", - "fieldtype": "Text", - "fieldname": "original_name", - "read_only": 1, - "hidden": 1, - "print_hide": 1, - "no_copy": 1 - }) + if self.is_submittable and\ + not frappe.db.get_value('DocField', {'fieldname': 'amended_from', 'parent': self.name}): + + self.append("fields", { + "label": "Original Name", + "fieldtype": "Text", + "fieldname": "original_name", + "read_only": 1, + "hidden": 1, + "print_hide": 1, + "no_copy": 1 + }) def make_repeatable(self): """If allow_auto_repeat is set, add auto_repeat custom field.""" From 413383bf5cbbe27fb2b93c23e761e0a5b8b7f1f4 Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 16 Apr 2021 13:38:06 +0530 Subject: [PATCH 07/33] fix: condition in make_cancellable --- 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 aad0321fa0..c6f6b628cc 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -593,7 +593,7 @@ class DocType(Document): def make_cancellable(self): """If is_submittable is set, add original_name docfield.""" if self.is_submittable and\ - not frappe.db.get_value('DocField', {'fieldname': 'amended_from', 'parent': self.name}): + not frappe.db.get_value('DocField', {'fieldname': 'original_name', 'parent': self.name}): self.append("fields", { "label": "Original Name", From 2cf5915eee428e026de8b4ad9b8c75c60d756eee Mon Sep 17 00:00:00 2001 From: Prssanna Desai Date: Fri, 16 Apr 2021 13:38:33 +0530 Subject: [PATCH 08/33] fix: use get_meta Co-authored-by: Faris Ansari --- .../v13_0/add_original_name_docfield_to_submittable_doctypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py b/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py index d870e63305..c5080cc692 100644 --- a/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py +++ b/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py @@ -2,7 +2,7 @@ import frappe def execute(): for doctype in frappe.db.get_all('DocType'): - doctype = frappe.get_doc("DocType", doctype.name) + doctype = frappe.get_meta(doctype.name) if doctype.is_submittable and frappe.db.table_exists(doctype.name): doctype.make_cancellable() frappe.reload_doctype(doctype.name) From 209ece8b6cc23fce390d8bb04d5463a85320dd34 Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 16 Apr 2021 14:03:36 +0530 Subject: [PATCH 09/33] fix: delete test submittable doctype --- frappe/tests/test_naming.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frappe/tests/test_naming.py b/frappe/tests/test_naming.py index afaabcc805..7be2cc3ef7 100644 --- a/frappe/tests/test_naming.py +++ b/frappe/tests/test_naming.py @@ -119,7 +119,7 @@ class TestNaming(unittest.TestCase): frappe.db.sql("""delete from `tabSeries` where name = %s""", series) def test_naming_for_cancelled_and_amended_doc(self): - frappe.get_doc({ + submittable_doctype = frappe.get_doc({ "doctype": "DocType", "module": "Core", "custom": 1, @@ -149,3 +149,5 @@ class TestNaming(unittest.TestCase): amended_doc.submit() amended_doc.cancel() self.assertEqual(amended_doc.name, "{}-2".format(original_name)) + + submittable_doctype.delete() \ No newline at end of file From 0c603f0d769536d3351386cb2cd7aaccd99797a5 Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 16 Apr 2021 17:27:12 +0530 Subject: [PATCH 10/33] test: fix cancel docs tests --- frappe/core/doctype/doctype/test_doctype.py | 4 ++++ .../add_original_name_docfield_to_submittable_doctypes.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py index 9c492d2c36..5a53600fff 100644 --- a/frappe/core/doctype/doctype/test_doctype.py +++ b/frappe/core/doctype/doctype/test_doctype.py @@ -350,6 +350,7 @@ class TestDocType(unittest.TestCase): dump_docs = json.dumps(docs.get('docs')) cancel_all_linked_docs(dump_docs) data_link_doc.cancel() + data_doc.name = '{}-1'.format(data_doc.name) data_doc.load_from_db() self.assertEqual(data_link_doc.docstatus, 2) self.assertEqual(data_doc.docstatus, 2) @@ -435,7 +436,10 @@ class TestDocType(unittest.TestCase): self.assertRaises(frappe.LinkExistsError, data_link_doc_1.cancel) data_doc.load_from_db() + + data_doc_2.name = '{}-1'.format(data_doc_2.name) data_doc_2.load_from_db() + self.assertEqual(data_link_doc_1.docstatus, 2) #linked doc is canceled diff --git a/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py b/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py index c5080cc692..eccff2334f 100644 --- a/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py +++ b/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py @@ -2,7 +2,7 @@ import frappe def execute(): for doctype in frappe.db.get_all('DocType'): - doctype = frappe.get_meta(doctype.name) + doctype = frappe.get_doc('DocType', doctype.name) if doctype.is_submittable and frappe.db.table_exists(doctype.name): doctype.make_cancellable() frappe.reload_doctype(doctype.name) From b550e54f15d02bbb14d79c70344a89f0f73d9c33 Mon Sep 17 00:00:00 2001 From: prssanna Date: Thu, 29 Apr 2021 17:31:56 +0530 Subject: [PATCH 11/33] fix: add column in patch --- .../add_original_name_docfield_to_submittable_doctypes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py b/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py index eccff2334f..d17242e90a 100644 --- a/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py +++ b/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py @@ -1,9 +1,11 @@ import frappe +from frappe.database.schema import add_column def execute(): for doctype in frappe.db.get_all('DocType'): doctype = frappe.get_doc('DocType', doctype.name) if doctype.is_submittable and frappe.db.table_exists(doctype.name): doctype.make_cancellable() - frappe.reload_doctype(doctype.name) + if not frappe.db.has_column(doctype.name, 'original_name'): + add_column(doctype.name, 'original_name', 'Text') doctype.db_update_all() From 081677c6c4bf6190c804fb432ee2e83d14c74dda Mon Sep 17 00:00:00 2001 From: Prssanna Desai Date: Fri, 7 May 2021 11:30:35 +0530 Subject: [PATCH 12/33] fix: typo in test --- 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 7be2cc3ef7..e7933ec7b3 100644 --- a/frappe/tests/test_naming.py +++ b/frappe/tests/test_naming.py @@ -131,7 +131,7 @@ class TestNaming(unittest.TestCase): "name": 'Submittable Doctype' }).insert() - doc = frappe.new_doc('Submittable DocType') + doc = frappe.new_doc('Submittable Doctype') doc.save() original_name = doc.name From 1bf90d18ee8159554b152c72a5a0341d2560f462 Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Tue, 15 Jun 2021 17:17:08 +0530 Subject: [PATCH 13/33] perf-fix: Remove meta from pickling overhead --- frappe/model/base_document.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index af696e116d..9447e60529 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -83,11 +83,15 @@ class BaseDocument(object): @property def meta(self): - if not hasattr(self, "_meta"): + if not getattr(self, "_meta", None): self._meta = frappe.get_meta(self.doctype) return self._meta + def __getstate__(self): + self._meta = None + return self.__dict__ + def update(self, d): """ Update multiple fields of a doctype using a dictionary of key-value pairs. From 23231fcbba400a0ad0af7b2f1cf9a5e10c49f83e Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Tue, 15 Jun 2021 19:01:15 +0200 Subject: [PATCH 14/33] fix: translation of email salutation --- frappe/public/js/frappe/views/communication.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js index e2aaec553d..6c1885c458 100755 --- a/frappe/public/js/frappe/views/communication.js +++ b/frappe/public/js/frappe/views/communication.js @@ -728,7 +728,7 @@ frappe.views.CommunicationComposer = class { const SALUTATION_END_COMMENT = ""; if (this.real_name && !message.includes(SALUTATION_END_COMMENT)) { this.message = ` -

${__('Dear')} ${this.real_name},

+

${__('Dear {0},', [this.real_name], 'Salutation in new email')},

${SALUTATION_END_COMMENT}
${message} `; From f8ec3d711ca600875a15f6132660fc13de296651 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Thu, 24 Jun 2021 18:43:12 +0200 Subject: [PATCH 15/33] feat: print branch and commit on `bench version` --- frappe/commands/utils.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index c16de497ec..b944f02af7 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -770,19 +770,23 @@ def set_config(context, key, value, global_=False, parse=False, as_dict=False): @click.command('version') def get_version(): "Show the versions of all the installed apps" + from git import Repo from frappe.utils.change_log import get_app_branch frappe.init('') - for m in sorted(frappe.get_all_apps()): - branch_name = get_app_branch(m) - module = frappe.get_module(m) - app_hooks = frappe.get_module(m + ".hooks") + for app in sorted(frappe.get_all_apps()): + branch_name = get_app_branch(app) + module = frappe.get_module(app) + app_hooks = frappe.get_module(app + ".hooks") + repo = Repo(frappe.get_app_path(app, "..")) + branch = repo.head.ref.name + commit = repo.head.ref.commit.hexsha[:7] if hasattr(app_hooks, '{0}_version'.format(branch_name)): - print("{0} {1}".format(m, getattr(app_hooks, '{0}_version'.format(branch_name)))) + click.echo("{0} {1} {2} ({3})".format(app, getattr(app_hooks, '{0}_version'.format(branch_name)), branch, commit)) elif hasattr(module, "__version__"): - print("{0} {1}".format(m, module.__version__)) + click.echo("{0} {1} {2} ({3})".format(app, module.__version__, branch, commit)) @click.command('rebuild-global-search') From 892cf038806224f069c67559865ce538111830b2 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Fri, 25 Jun 2021 13:21:53 +0200 Subject: [PATCH 16/33] feat: translate connection group label --- frappe/public/js/frappe/form/templates/form_links.html | 2 +- frappe/public/js/frappe/form/templates/report_links.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/templates/form_links.html b/frappe/public/js/frappe/form/templates/form_links.html index e16516e652..57edb69a15 100644 --- a/frappe/public/js/frappe/form/templates/form_links.html +++ b/frappe/public/js/frappe/form/templates/form_links.html @@ -5,7 +5,7 @@ {% } %}
{% for (let j=0; j < transactions[i].items.length; j++) { %} {% let doctype = transactions[i].items[j]; %} diff --git a/frappe/public/js/frappe/form/templates/report_links.html b/frappe/public/js/frappe/form/templates/report_links.html index 3b69586d32..b820ec3a52 100644 --- a/frappe/public/js/frappe/form/templates/report_links.html +++ b/frappe/public/js/frappe/form/templates/report_links.html @@ -5,7 +5,7 @@ {% } %}
{% for (let j=0; j < reports[i].items.length; j++) { %} {% let report = reports[i].items[j]; %} From b7fb1d475ecfab9be51d312e9ce2f79281916c73 Mon Sep 17 00:00:00 2001 From: leela Date: Sat, 26 Jun 2021 09:37:08 +0530 Subject: [PATCH 17/33] fix: workspace loading error Workspace loads to fail if there are no links in any extended workspaces. --- frappe/desk/desktop.py | 1 + frappe/desk/doctype/workspace/workspace.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/desk/desktop.py b/frappe/desk/desktop.py index 0a7d436169..cdab7d6d1b 100644 --- a/frappe/desk/desktop.py +++ b/frappe/desk/desktop.py @@ -368,6 +368,7 @@ def get_desktop_page(page): 'allow_customization': not wspace.doc.disable_user_customization } except DoesNotExistError: + frappe.log_error(frappe.get_traceback()) return {} @frappe.whitelist() diff --git a/frappe/desk/doctype/workspace/workspace.py b/frappe/desk/doctype/workspace/workspace.py index 0b5babc8d9..41b0227f2a 100644 --- a/frappe/desk/doctype/workspace/workspace.py +++ b/frappe/desk/doctype/workspace/workspace.py @@ -43,19 +43,19 @@ class Workspace(Document): def get_link_groups(self): cards = [] - current_card = { + current_card = frappe._dict({ "label": "Link", "type": "Card Break", "icon": None, "hidden": False, - } + }) card_links = [] for link in self.links: link = link.as_dict() if link.type == "Card Break": - if card_links and (not current_card.only_for or current_card.only_for == frappe.get_system_settings('country')): + if card_links and (not current_card.only_for or current_card.only_for == frappe.get_system_settings('country')): current_card['links'] = card_links cards.append(current_card) From 49832067745ed334024d28b54ae525108386feb2 Mon Sep 17 00:00:00 2001 From: conncampbell Date: Sat, 26 Jun 2021 12:27:23 -0600 Subject: [PATCH 18/33] fix: missing otp form template html in prior commit. --- frappe/templates/includes/login/login.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/frappe/templates/includes/login/login.js b/frappe/templates/includes/login/login.js index 355e8151f9..3bcd31e93b 100644 --- a/frappe/templates/includes/login/login.js +++ b/frappe/templates/includes/login/login.js @@ -291,11 +291,16 @@ var verify_token = function (event) { } var request_otp = function (r) { - const otp_form_template = '{{ _("Verification") }}{{ _("Verify") }}'; $('.login-content').empty(); - $('.login-content:visible').append( - $('
').attr({ 'id': 'twofactor_div' }).html(otp_form_template) - ); + $('.login-content:visible').append($('
').attr({ 'id': 'twofactor_div' }).html( + '
\ +
\ + {{ _("Verification") }}\ +
\ +
\ + \ + \ +
')); // add event handler for submit button verify_token(); } From 117a729c8da47a3ca90d73d775f06eb2ccb13671 Mon Sep 17 00:00:00 2001 From: gavin Date: Wed, 30 Jun 2021 10:51:44 +0530 Subject: [PATCH 19/33] refactor(minor): login-content template Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- frappe/templates/includes/login/login.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/frappe/templates/includes/login/login.js b/frappe/templates/includes/login/login.js index 3bcd31e93b..4400578862 100644 --- a/frappe/templates/includes/login/login.js +++ b/frappe/templates/includes/login/login.js @@ -292,15 +292,18 @@ var verify_token = function (event) { var request_otp = function (r) { $('.login-content').empty(); - $('.login-content:visible').append($('
').attr({ 'id': 'twofactor_div' }).html( - '
\ -
\ - {{ _("Verification") }}\ -
\ -
\ - \ - \ -
')); + $('.login-content:visible').append( + `
+
+
+ {{ _("Verification") }} +
+
+ + +
+
` + ); // add event handler for submit button verify_token(); } From 36a3504b29db2ef7daaf8f4c331b76d9360a025c Mon Sep 17 00:00:00 2001 From: marination Date: Tue, 29 Jun 2021 18:11:13 +0530 Subject: [PATCH 20/33] fix: Premature commit via notification's `send_an_email` --- frappe/core/doctype/communication/email.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index d35c118550..7ffbe6781d 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -85,8 +85,6 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received = if attachments: add_attachments(comm.name, attachments) - frappe.db.commit() - if cint(send_email): if not comm.get_outgoing_email_account(): frappe.throw(msg=OUTGOING_EMAIL_ACCOUNT_MISSING, exc=frappe.OutgoingEmailError) From 6bb96419d4a9a24e3f733ffbd0c50ef8ea951af7 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Wed, 30 Jun 2021 15:29:49 +0530 Subject: [PATCH 21/33] fix: Safe checks while setting doctypes_with_web_view cache --- frappe/website/router.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/website/router.py b/frappe/website/router.py index a9e2f68fe5..9809a73e48 100644 --- a/frappe/website/router.py +++ b/frappe/website/router.py @@ -270,7 +270,7 @@ def get_doctypes_with_web_view(): doctypes_with_web_view = frappe.get_all('DocType', fields=['name', 'module'], filters=dict(has_web_view=1)) module_app_map = frappe.local.module_app - doctypes += [d.name for d in doctypes_with_web_view if module_app_map[frappe.scrub(d.module)] in installed_apps] + doctypes += [d.name for d in doctypes_with_web_view if module_app_map.get(frappe.scrub(d.module)) in installed_apps] return doctypes return frappe.cache().get_value('doctypes_with_web_view', _get) From dc514905f22b8be0aa802bf9e0f7ad8ff77dd953 Mon Sep 17 00:00:00 2001 From: gavin Date: Wed, 30 Jun 2021 15:49:14 +0530 Subject: [PATCH 22/33] chore: Update CODEOWNERS --- CODEOWNERS | 3 --- 1 file changed, 3 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 92723ab035..2dff157294 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -4,13 +4,10 @@ # the repo. Unless a later match takes precedence, * @frappe/frappe-review-team -website/ @prssanna -web_form/ @prssanna templates/ @surajshetty3416 www/ @surajshetty3416 integrations/ @leela patches/ @surajshetty3416 -dashboard/ @prssanna email/ @leela event_streaming/ @ruchamahabal data_import* @netchampfaris From 3d36b671528141e72a6de413309f2ec42f6d63e2 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Wed, 30 Jun 2021 17:36:27 +0530 Subject: [PATCH 23/33] fix: Hide "Attach File" in form if max limit reached --- frappe/public/js/frappe/form/sidebar/attachments.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/sidebar/attachments.js b/frappe/public/js/frappe/form/sidebar/attachments.js index 4f116df63e..538534e5cf 100644 --- a/frappe/public/js/frappe/form/sidebar/attachments.js +++ b/frappe/public/js/frappe/form/sidebar/attachments.js @@ -11,7 +11,7 @@ frappe.ui.form.Attachments = class Attachments { this.parent.find(".add-attachment-btn").click(function() { me.new_attachment(); }); - this.add_attachment_wrapper = this.parent.find(".add_attachment").parent(); + this.add_attachment_wrapper = this.parent.find(".add-attachment-btn"); this.attachments_label = this.parent.find(".attachments-label"); } max_reached(raise_exception=false) { @@ -39,7 +39,7 @@ frappe.ui.form.Attachments = class Attachments { this.parent.find(".attachment-row").remove(); var max_reached = this.max_reached(); - this.add_attachment_wrapper.toggleClass("hide", !max_reached); + this.add_attachment_wrapper.toggle(!max_reached); // add attachment objects var attachments = this.get_attachments(); From fd51ba7fcc0f50ce0159e41f2636448af5a708d6 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 30 Jun 2021 16:58:54 +0000 Subject: [PATCH 24/33] chore(deps): [security] bump socket.io-parser from 3.3.0 to 3.3.2 Bumps [socket.io-parser](https://github.com/socketio/socket.io-parser) from 3.3.0 to 3.3.2. **This update includes a security fix.** - [Release notes](https://github.com/socketio/socket.io-parser/releases) - [Changelog](https://github.com/socketio/socket.io-parser/blob/3.3.2/CHANGELOG.md) - [Commits](https://github.com/socketio/socket.io-parser/compare/3.3.0...3.3.2) Signed-off-by: dependabot-preview[bot] --- yarn.lock | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7b1fb981dd..ddb5623e5e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1381,12 +1381,12 @@ component-bind@1.0.0: resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= -component-emitter@1.2.1, component-emitter@^1.2.0: +component-emitter@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= -component-emitter@~1.3.0: +component-emitter@^1.2.0, component-emitter@~1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -1713,28 +1713,14 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@^3.0.1: +debug@^3.0.1, debug@^3.1.0, debug@^3.2.6: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" -debug@^3.1.0, debug@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -debug@^4.1.1, debug@~4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -debug@^4.2.0, debug@^4.3.1: +debug@^4.1.1, debug@^4.2.0, debug@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== @@ -1748,6 +1734,13 @@ debug@~3.1.0: dependencies: ms "2.0.0" +debug@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + decamelize@^1.0.0, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -6425,11 +6418,11 @@ socket.io-client@2.4.0: to-array "0.1.4" socket.io-parser@~3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" - integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng== + version "3.3.2" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.2.tgz#ef872009d0adcf704f2fbe830191a14752ad50b6" + integrity sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg== dependencies: - component-emitter "1.2.1" + component-emitter "~1.3.0" debug "~3.1.0" isarray "2.0.1" From d58d2ac77f0ede883df774710c9b5e1d9c790c67 Mon Sep 17 00:00:00 2001 From: Ankush Date: Wed, 30 Jun 2021 23:05:05 +0530 Subject: [PATCH 25/33] ci(cypress): use env variable for key (#13616) documentation ref: https://docs.cypress.io/guides/guides/command-line#cypress-run --- .github/workflows/ui-tests.yml | 2 ++ frappe/commands/utils.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index f2f43f10f8..f342c0709e 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -105,3 +105,5 @@ jobs: - name: UI Tests run: cd ~/frappe-bench/ && bench --site test_site run-ui-tests frappe --headless --parallel --ci-build-id $GITHUB_RUN_ID + env: + CYPRESS_RECORD_KEY: 4a48f41c-11b3-425b-aa88-c58048fa69eb diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index c16de497ec..b6e48e3388 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -661,7 +661,7 @@ def run_ui_tests(context, app, headless=False, parallel=True, ci_build_id=None): frappe.commands.popen("yarn add cypress@^6 cypress-file-upload@^5 --no-lockfile") # run for headless mode - run_or_open = 'run --browser firefox --record --key 4a48f41c-11b3-425b-aa88-c58048fa69eb' if headless else 'open' + run_or_open = 'run --browser firefox --record' if headless else 'open' command = '{site_env} {password_env} {cypress} {run_or_open}' formatted_command = command.format(site_env=site_env, password_env=password_env, cypress=cypress_path, run_or_open=run_or_open) From 02e735da8ebe173ca931585ee827c2048e97a7fb Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 1 Jul 2021 22:06:26 +0530 Subject: [PATCH 26/33] fix: Do not set base template for resource --- frappe/website/page_renderers/template_page.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frappe/website/page_renderers/template_page.py b/frappe/website/page_renderers/template_page.py index 5134313c83..249c998192 100644 --- a/frappe/website/page_renderers/template_page.py +++ b/frappe/website/page_renderers/template_page.py @@ -150,8 +150,7 @@ class TemplatePage(BaseTemplatePage): def set_page_properties(self): self.context.base_template = self.context.base_template \ - or get_base_template(self.path) \ - or 'templates/web.html' + or get_base_template(self.path) self.context.basepath = self.basepath self.context.basename = self.basename self.context.name = self.name From a93bb670308a26cc7265c610300386dd7860232f Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 1 Jul 2021 22:08:15 +0530 Subject: [PATCH 27/33] test: Add test case to validate raw file load --- frappe/tests/test_website.py | 7 +++++++ frappe/www/_test/assets/css_asset.css | 1 + frappe/www/_test/assets/js_asset.js | 1 + 3 files changed, 9 insertions(+) create mode 100644 frappe/www/_test/assets/css_asset.css create mode 100644 frappe/www/_test/assets/js_asset.js diff --git a/frappe/tests/test_website.py b/frappe/tests/test_website.py index 5c19d3935c..7241bbb508 100644 --- a/frappe/tests/test_website.py +++ b/frappe/tests/test_website.py @@ -244,6 +244,13 @@ class TestWebsite(unittest.TestCase): self.assertIn("", content) self.assertIn("background-color: var(--bg-color);", content) + def test_raw_assets_are_loaded(self): + content = get_response_content('/_test/assets/js_asset.js') + self.assertEqual("console.log('in');", content) + + content = get_response_content('/_test/assets/css_asset.css') + self.assertEqual("""body{color:red}""", content) + def test_breadcrumbs(self): content = get_response_content('/_test/_test_folder/_test_page') self.assertIn('Test TOC', content) diff --git a/frappe/www/_test/assets/css_asset.css b/frappe/www/_test/assets/css_asset.css new file mode 100644 index 0000000000..363a06397a --- /dev/null +++ b/frappe/www/_test/assets/css_asset.css @@ -0,0 +1 @@ +body{color:red} \ No newline at end of file diff --git a/frappe/www/_test/assets/js_asset.js b/frappe/www/_test/assets/js_asset.js new file mode 100644 index 0000000000..b39f5af3dd --- /dev/null +++ b/frappe/www/_test/assets/js_asset.js @@ -0,0 +1 @@ +console.log('in'); \ No newline at end of file From 4363e51c6dd6510d427e5347b477552d88eab9dd Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 1 Jul 2021 22:10:02 +0530 Subject: [PATCH 28/33] test: Fix improper tests for website rendering --- frappe/templates/test/_test_base.html | 11 ---------- .../test/_test_base_breadcrumbs.html | 20 +++++++++++++++++++ frappe/tests/test_website.py | 4 ++-- frappe/www/_test/_test_folder/_test_page.html | 1 + frappe/www/_test/_test_folder/_test_page.py | 2 +- frappe/www/_test/_test_folder/index.md | 4 ++-- 6 files changed, 26 insertions(+), 16 deletions(-) create mode 100644 frappe/templates/test/_test_base_breadcrumbs.html diff --git a/frappe/templates/test/_test_base.html b/frappe/templates/test/_test_base.html index 17caf8df1b..1d5019df37 100644 --- a/frappe/templates/test/_test_base.html +++ b/frappe/templates/test/_test_base.html @@ -1,20 +1,9 @@ - {%- block style %} - {% if colocated_css -%} - - {%- endif %} - {%- endblock -%} - {% include "templates/includes/breadcrumbs.html" %}

This is for testing

{% block content %}{% endblock %} - {%- block script %} - {% if colocated_js -%} - - {%- endif %} - {%- endblock %} diff --git a/frappe/templates/test/_test_base_breadcrumbs.html b/frappe/templates/test/_test_base_breadcrumbs.html new file mode 100644 index 0000000000..17caf8df1b --- /dev/null +++ b/frappe/templates/test/_test_base_breadcrumbs.html @@ -0,0 +1,20 @@ + + + + {%- block style %} + {% if colocated_css -%} + + {%- endif %} + {%- endblock -%} + + + {% include "templates/includes/breadcrumbs.html" %} +

This is for testing

+ {% block content %}{% endblock %} + {%- block script %} + {% if colocated_js -%} + + {%- endif %} + {%- endblock %} + + diff --git a/frappe/tests/test_website.py b/frappe/tests/test_website.py index 7241bbb508..ae768d7804 100644 --- a/frappe/tests/test_website.py +++ b/frappe/tests/test_website.py @@ -253,12 +253,12 @@ class TestWebsite(unittest.TestCase): def test_breadcrumbs(self): content = get_response_content('/_test/_test_folder/_test_page') - self.assertIn('Test TOC', content) + self.assertIn('Test Folder', content) self.assertIn(' Test Page', content) content = get_response_content('/_test/_test_folder/index') self.assertIn(' Test', content) - self.assertIn('Test TOC', content) + self.assertIn('Test Folder', content) def test_get_context_without_context_object(self): content = get_response_content('/_test/_test_no_context') diff --git a/frappe/www/_test/_test_folder/_test_page.html b/frappe/www/_test/_test_folder/_test_page.html index 123d619e38..79bc96c568 100644 --- a/frappe/www/_test/_test_folder/_test_page.html +++ b/frappe/www/_test/_test_folder/_test_page.html @@ -1,3 +1,4 @@ +{% extends base_template_path %} {% block content %} {% include "templates/includes/web_sidebar.html" %}

Test content

diff --git a/frappe/www/_test/_test_folder/_test_page.py b/frappe/www/_test/_test_folder/_test_page.py index 1813a06bac..3d4a645f9b 100644 --- a/frappe/www/_test/_test_folder/_test_page.py +++ b/frappe/www/_test/_test_folder/_test_page.py @@ -1,3 +1,3 @@ def get_context(context): - context.base_template_path = 'frappe/templates/test/_test_base.html' + context.base_template_path = 'frappe/templates/test/_test_base_breadcrumbs.html' context.add_breadcrumbs = 1 diff --git a/frappe/www/_test/_test_folder/index.md b/frappe/www/_test/_test_folder/index.md index 1a5a9e7f81..ca8c55e9d5 100644 --- a/frappe/www/_test/_test_folder/index.md +++ b/frappe/www/_test/_test_folder/index.md @@ -1,9 +1,9 @@ --- -title: Test TOC +title: Test Folder add_breadcrumbs: 1 show_sidebar: 1 +base_template: templates/web.html --- - # Index {index} \ No newline at end of file From 35521327897a2fe38ff9bfb1389ff18723a70231 Mon Sep 17 00:00:00 2001 From: leela Date: Fri, 2 Jul 2021 11:25:02 +0530 Subject: [PATCH 29/33] fix: remove not needed six import --- frappe/model/document.py | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/model/document.py b/frappe/model/document.py index 0b2ae5895f..99585bb26c 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -6,7 +6,6 @@ from frappe import _, msgprint, is_whitelisted from frappe.utils import flt, cstr, now, get_datetime_str, file_lock, date_diff from frappe.model.base_document import BaseDocument, get_controller from frappe.model.naming import set_new_name, rename_cancelled_doc -from six import iteritems, string_types from werkzeug.exceptions import NotFound, Forbidden import hashlib, json from frappe.model import optional_fields, table_fields From f31d01a2a645ea5c2aebaeeb02cdb97b086ef356 Mon Sep 17 00:00:00 2001 From: leela Date: Fri, 2 Jul 2021 17:43:16 +0530 Subject: [PATCH 30/33] Revert "Merge pull request #13244 from prssanna/amended-doc-naming" This reverts commit 58b95662c2f704258f83ad72d4a0c942ae14f778, reversing changes made to c553b7e23a5c70f1c05b08850a419ac23fba7aa7. --- frappe/core/doctype/doctype/doctype.py | 40 +++++--------- frappe/core/doctype/doctype/test_doctype.py | 4 -- frappe/model/document.py | 10 +--- frappe/model/naming.py | 52 ++----------------- frappe/patches.txt | 1 - ...l_name_docfield_to_submittable_doctypes.py | 11 ---- frappe/public/js/frappe/form/form.js | 24 ++++----- frappe/public/js/frappe/router.js | 6 --- frappe/tests/test_naming.py | 34 ------------ 9 files changed, 27 insertions(+), 155 deletions(-) delete mode 100644 frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index da410b3e0b..3cdc45ea08 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -70,7 +70,6 @@ class DocType(Document): if not self.istable: validate_permissions(self) - self.make_cancellable() self.make_amendable() self.make_repeatable() self.validate_nestedset() @@ -569,33 +568,18 @@ class DocType(Document): def make_amendable(self): """If is_submittable is set, add amended_from docfields.""" - if self.is_submittable and\ - not frappe.db.get_value('DocField', {'fieldname': 'amended_from', 'parent': self.name}): - - self.append("fields", { - "label": "Amended From", - "fieldtype": "Link", - "fieldname": "amended_from", - "options": self.name, - "read_only": 1, - "print_hide": 1, - "no_copy": 1 - }) - - def make_cancellable(self): - """If is_submittable is set, add original_name docfield.""" - if self.is_submittable and\ - not frappe.db.get_value('DocField', {'fieldname': 'original_name', 'parent': self.name}): - - self.append("fields", { - "label": "Original Name", - "fieldtype": "Text", - "fieldname": "original_name", - "read_only": 1, - "hidden": 1, - "print_hide": 1, - "no_copy": 1 - }) + if self.is_submittable: + if not frappe.db.sql("""select name from tabDocField + where fieldname = 'amended_from' and parent = %s""", self.name): + self.append("fields", { + "label": "Amended From", + "fieldtype": "Link", + "fieldname": "amended_from", + "options": self.name, + "read_only": 1, + "print_hide": 1, + "no_copy": 1 + }) def make_repeatable(self): """If allow_auto_repeat is set, add auto_repeat custom field.""" diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py index fbb224fce7..1e1a01a685 100644 --- a/frappe/core/doctype/doctype/test_doctype.py +++ b/frappe/core/doctype/doctype/test_doctype.py @@ -348,7 +348,6 @@ class TestDocType(unittest.TestCase): dump_docs = json.dumps(docs.get('docs')) cancel_all_linked_docs(dump_docs) data_link_doc.cancel() - data_doc.name = '{}-1'.format(data_doc.name) data_doc.load_from_db() self.assertEqual(data_link_doc.docstatus, 2) self.assertEqual(data_doc.docstatus, 2) @@ -434,10 +433,7 @@ class TestDocType(unittest.TestCase): self.assertRaises(frappe.LinkExistsError, data_link_doc_1.cancel) data_doc.load_from_db() - - data_doc_2.name = '{}-1'.format(data_doc_2.name) data_doc_2.load_from_db() - self.assertEqual(data_link_doc_1.docstatus, 2) #linked doc is canceled diff --git a/frappe/model/document.py b/frappe/model/document.py index 99585bb26c..61160e1f01 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -5,7 +5,7 @@ import time from frappe import _, msgprint, is_whitelisted from frappe.utils import flt, cstr, now, get_datetime_str, file_lock, date_diff from frappe.model.base_document import BaseDocument, get_controller -from frappe.model.naming import set_new_name, rename_cancelled_doc +from frappe.model.naming import set_new_name from werkzeug.exceptions import NotFound, Forbidden import hashlib, json from frappe.model import optional_fields, table_fields @@ -917,14 +917,6 @@ class Document(BaseDocument): @whitelist.__func__ def _cancel(self): """Cancel the document. Sets `docstatus` = 2, then saves.""" - - # for backward compatibility - if self.amended_from and not self.original_name: - self.original_name = None - else: - self.original_name = self.name - - self.name = rename_cancelled_doc(self) self.docstatus = 2 self.save() diff --git a/frappe/model/naming.py b/frappe/model/naming.py index ed037adb0d..fe136adce8 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -221,16 +221,6 @@ def revert_series_if_last(key, name, doc=None): * prefix = #### and hashes = 2021 (hash doesn't exist) * will search hash in key then accordingly get prefix = "" """ - - if hasattr(doc, 'amended_from'): - # do not revert if doc is amended, since cancelled docs still exist - if doc.docstatus != 2 and doc.amended_from: - return - - # for first cancelled doc - if doc.docstatus == 2 and not doc.amended_from and doc.original_name: - name = doc.original_name - if ".#" in key: prefix, hashes = key.rsplit(".", 1) if "#" not in hashes: @@ -314,48 +304,14 @@ def append_number_if_name_exists(doctype, value, fieldname="name", separator="-" def _set_amended_name(doc): - if doc.original_name: - doc.name = doc.original_name - else: - original_name = get_original_name(doc) - doc.name = doc.amended_from - - # rename original doc to next name in series, and set amended doc name as original name - next_name_in_series = get_new_name_from_amended_from(doc) - frappe.rename_doc(doc.doctype, original_name, next_name_in_series, force=True, show_alert=False) - doc.name = original_name - doc.amended_from = next_name_in_series - doc.original_name = original_name - - return doc.name - -def get_original_name(doc): - # get original doc name from chain of amended docs - amended_from = original_name = doc.amended_from - while amended_from: - original_name = amended_from - amended_from = frappe.db.get_value(doc.doctype, amended_from, "amended_from") - - return original_name - -def get_new_name_from_amended_from(doc): am_id = 1 - am_prefix = doc.name - if frappe.db.get_value(doc.doctype, doc.name, "amended_from"): + am_prefix = doc.amended_from + if frappe.db.get_value(doc.doctype, doc.amended_from, "amended_from"): am_id = cint(doc.amended_from.split("-")[-1]) + 1 am_prefix = "-".join(doc.amended_from.split("-")[:-1]) # except the last hyphen - new_name = am_prefix + "-" + str(am_id) - if new_name == doc.name: - am_id += 1 - new_name = am_prefix + "-" + str(am_id) - return new_name - -def rename_cancelled_doc(doc): - doc = frappe.parse_json(doc) - new_name = get_new_name_from_amended_from(doc) - frappe.rename_doc(doc.doctype, doc.name, new_name, force=True, show_alert=False) - return new_name + doc.name = am_prefix + "-" + str(am_id) + return doc.name def _field_autoname(autoname, doc, skip_slicing=None): diff --git a/frappe/patches.txt b/frappe/patches.txt index 833d85423b..7605d8ea2b 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -180,4 +180,3 @@ frappe.patches.v12_0.rename_uploaded_files_with_proper_name frappe.patches.v13_0.queryreport_columns frappe.patches.v13_0.jinja_hook frappe.patches.v13_0.update_notification_channel_if_empty -frappe.patches.v13_0.add_original_name_docfield_to_submittable_doctypes diff --git a/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py b/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py deleted file mode 100644 index d17242e90a..0000000000 --- a/frappe/patches/v13_0/add_original_name_docfield_to_submittable_doctypes.py +++ /dev/null @@ -1,11 +0,0 @@ -import frappe -from frappe.database.schema import add_column - -def execute(): - for doctype in frappe.db.get_all('DocType'): - doctype = frappe.get_doc('DocType', doctype.name) - if doctype.is_submittable and frappe.db.table_exists(doctype.name): - doctype.make_cancellable() - if not frappe.db.has_column(doctype.name, 'original_name'): - add_column(doctype.name, 'original_name', 'Text') - doctype.db_update_all() diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 30f023c987..8064f90a98 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -770,36 +770,32 @@ frappe.ui.form.Form = class FrappeForm { } _cancel(btn, callback, on_error, skip_confirm) { + const me = this; const cancel_doc = () => { frappe.validated = true; - this.script_manager.trigger("before_cancel").then(() => { + me.script_manager.trigger("before_cancel").then(() => { if (!frappe.validated) { - return this.handle_save_fail(btn, on_error); + return me.handle_save_fail(btn, on_error); } - const original_name = this.docname; - const after_cancel = (r) => { + var after_cancel = function(r) { if (r.exc) { - this.handle_save_fail(btn, on_error); + me.handle_save_fail(btn, on_error); } else { frappe.utils.play_sound("cancel"); + me.refresh(); callback && callback(); - this.script_manager.trigger("after_cancel"); - frappe.run_serially([ - () => this.rename_notify(this.doctype, original_name, r.docs[0].name), - () => frappe.router.clear_re_route(this.doctype, original_name), - () => this.refresh(), - ]); + me.script_manager.trigger("after_cancel"); } }; - frappe.ui.form.save(this, "cancel", after_cancel, btn); + frappe.ui.form.save(me, "cancel", after_cancel, btn); }); } if (skip_confirm) { cancel_doc(); } else { - frappe.confirm(__("Permanently Cancel {0}?", [this.docname]), cancel_doc, this.handle_save_fail(btn, on_error)); + frappe.confirm(__("Permanently Cancel {0}?", [this.docname]), cancel_doc, me.handle_save_fail(btn, on_error)); } }; @@ -821,7 +817,7 @@ frappe.ui.form.Form = class FrappeForm { 'docname': this.doc.name }).then(is_amended => { if (is_amended) { - frappe.throw(__('This document is already amended, you cannot amend it again')); + frappe.throw(__('This document is already amended, you cannot ammend it again')); } this.validate_form_action("Amend"); var me = this; diff --git a/frappe/public/js/frappe/router.js b/frappe/public/js/frappe/router.js index 46544db919..12caf4ab94 100644 --- a/frappe/public/js/frappe/router.js +++ b/frappe/public/js/frappe/router.js @@ -235,12 +235,6 @@ frappe.router = { } }, - clear_re_route(doctype, docname) { - delete frappe.re_route[ - `${encodeURIComponent(frappe.router.slug(doctype))}/${encodeURIComponent(docname)}` - ]; - }, - set_title(sub_path) { if (frappe.route_titles[sub_path]) { frappe.utils.set_title(frappe.route_titles[sub_path]); diff --git a/frappe/tests/test_naming.py b/frappe/tests/test_naming.py index b716f063c4..557993882f 100644 --- a/frappe/tests/test_naming.py +++ b/frappe/tests/test_naming.py @@ -116,37 +116,3 @@ class TestNaming(unittest.TestCase): self.assertEqual(current_index.get('current'), 2) frappe.db.sql("""delete from `tabSeries` where name = %s""", series) - - def test_naming_for_cancelled_and_amended_doc(self): - submittable_doctype = frappe.get_doc({ - "doctype": "DocType", - "module": "Core", - "custom": 1, - "is_submittable": 1, - "permissions": [{ - "role": "System Manager", - "read": 1 - }], - "name": 'Submittable Doctype' - }).insert() - - doc = frappe.new_doc('Submittable Doctype') - doc.save() - original_name = doc.name - - doc.submit() - doc.cancel() - cancelled_name = doc.name - self.assertEqual(cancelled_name, "{}-1".format(original_name)) - - amended_doc = frappe.copy_doc(doc) - amended_doc.docstatus = 0 - amended_doc.amended_from = doc.name - amended_doc.save() - self.assertEqual(amended_doc.name, original_name) - - amended_doc.submit() - amended_doc.cancel() - self.assertEqual(amended_doc.name, "{}-2".format(original_name)) - - submittable_doctype.delete() \ No newline at end of file From 508f47e8717ddadaa0b692f8041b233d819b6b68 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sat, 3 Jul 2021 14:13:02 +0530 Subject: [PATCH 31/33] fix: Minified js load --- frappe/website/page_renderers/template_page.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/frappe/website/page_renderers/template_page.py b/frappe/website/page_renderers/template_page.py index 249c998192..3ece8ff5d0 100644 --- a/frappe/website/page_renderers/template_page.py +++ b/frappe/website/page_renderers/template_page.py @@ -70,7 +70,7 @@ class TemplatePage(BaseTemplatePage): self.set_pymodule() self.update_context() - self.setup_template() + self.setup_template_source() self.load_colocated_files() self.set_properties_from_source() self.post_process_context() @@ -118,7 +118,7 @@ class TemplatePage(BaseTemplatePage): if os.path.exists(os.path.join(self.app_path, self.pymodule_path)): self.pymodule_name = self.app + "." + self.pymodule_path.replace(os.path.sep, ".")[:-3] - def setup_template(self): + def setup_template_source(self): '''Setup template source, frontmatter and markdown conversion''' self.source = self.get_raw_template() self.extract_frontmatter() @@ -126,7 +126,6 @@ class TemplatePage(BaseTemplatePage): def update_context(self): self.set_page_properties() - self.set_properties_from_source() self.context.build_version = frappe.utils.get_build_version() if self.pymodule_name: @@ -202,13 +201,10 @@ class TemplatePage(BaseTemplatePage): frappe.errprint(frappe.utils.get_traceback()) def render_template(self): - if self.source: + if self.template_path.endswith('min.js'): + html = self.source # static + else: html = frappe.render_template(self.source, self.context) - elif self.template_path: - if self.path.endswith('min.js'): - html = self.get_raw_template() # static - else: - html = frappe.get_template(self.template_path).render(self.context) return html From fccd19a44cd248c35a0b8e1dd2f20f95060b2d7e Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sat, 3 Jul 2021 14:13:16 +0530 Subject: [PATCH 32/33] test: Add test to validate minified js load --- frappe/tests/test_website.py | 5 +++-- frappe/www/_test/assets/__init__.py | 0 frappe/www/_test/assets/js_asset.js | 1 - frappe/www/_test/assets/js_asset.min.js | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 frappe/www/_test/assets/__init__.py delete mode 100644 frappe/www/_test/assets/js_asset.js create mode 100644 frappe/www/_test/assets/js_asset.min.js diff --git a/frappe/tests/test_website.py b/frappe/tests/test_website.py index ae768d7804..f1c4f3b3f5 100644 --- a/frappe/tests/test_website.py +++ b/frappe/tests/test_website.py @@ -245,8 +245,9 @@ class TestWebsite(unittest.TestCase): self.assertIn("background-color: var(--bg-color);", content) def test_raw_assets_are_loaded(self): - content = get_response_content('/_test/assets/js_asset.js') - self.assertEqual("console.log('in');", content) + content = get_response_content('/_test/assets/js_asset.min.js') + # minified js files should not be passed through jinja renderer + self.assertEqual("//{% if title %} {{title}} {% endif %}\nconsole.log('in');", content) content = get_response_content('/_test/assets/css_asset.css') self.assertEqual("""body{color:red}""", content) diff --git a/frappe/www/_test/assets/__init__.py b/frappe/www/_test/assets/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/www/_test/assets/js_asset.js b/frappe/www/_test/assets/js_asset.js deleted file mode 100644 index b39f5af3dd..0000000000 --- a/frappe/www/_test/assets/js_asset.js +++ /dev/null @@ -1 +0,0 @@ -console.log('in'); \ No newline at end of file diff --git a/frappe/www/_test/assets/js_asset.min.js b/frappe/www/_test/assets/js_asset.min.js new file mode 100644 index 0000000000..e039292259 --- /dev/null +++ b/frappe/www/_test/assets/js_asset.min.js @@ -0,0 +1,2 @@ +//{% if title %} {{title}} {% endif %} +console.log('in'); \ No newline at end of file From bdfb53a50c52c8dedab8f05457d30044872111c9 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 1 Jul 2021 19:04:54 +0530 Subject: [PATCH 33/33] fix(Workspace): Pass doctype info for link item Without item.doctype, url for non standard reports in workspace cards doesn't set properly since doctype value is unidentified Sometimes, the whole workspace won't render because slug function breaks while recieving undefined object (cherry picked from commit 689e38b8610cc9e0b9b738d2774d0daa193dc309) --- frappe/public/js/frappe/widgets/links_widget.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/public/js/frappe/widgets/links_widget.js b/frappe/public/js/frappe/widgets/links_widget.js index 84758db592..2cc824899f 100644 --- a/frappe/public/js/frappe/widgets/links_widget.js +++ b/frappe/public/js/frappe/widgets/links_widget.js @@ -64,6 +64,7 @@ export default class LinksWidget extends Widget { const opts = { name: item.link_to, type: item.link_type, + doctype: item.doctype, is_query_report: item.is_query_report };