diff --git a/frappe/core/doctype/file/utils.py b/frappe/core/doctype/file/utils.py index b106ea67c5..035e0730b2 100644 --- a/frappe/core/doctype/file/utils.py +++ b/frappe/core/doctype/file/utils.py @@ -339,6 +339,7 @@ def attach_files_to_document(doc: "Document", event) -> None: "attached_to_name": doc.name, "attached_to_doctype": doc.doctype, "attached_to_field": df.fieldname, + "is_private": value.startswith("/private"), }, ) continue @@ -357,6 +358,49 @@ def attach_files_to_document(doc: "Document", event) -> None: doc.log_error("Error Attaching File") +def relink_files(doc, fieldname, temp_doc_name): + from frappe.utils.data import add_to_date, now_datetime + + """ + Relink files attached to incorrect document name to the new document name + by check if file with temp name exists that was created in last 60 minutes + """ + mislinked_file = frappe.db.exists( + "File", + { + "file_url": doc.get(fieldname), + "attached_to_name": temp_doc_name, + "attached_to_doctype": doc.doctype, + "attached_to_field": fieldname, + "creation": ( + "between", + [now_datetime() - add_to_date(date=now_datetime(), minutes=-60), now_datetime()], + ), + }, + ) + """If file exists, attach it to the new docname""" + if mislinked_file: + frappe.db.set_value( + "File", + mislinked_file, + field={ + "attached_to_name": doc.name, + "attached_to_doctype": doc.doctype, + "attached_to_field": fieldname, + }, + ) + return + + +def relink_mismatched_files(doc: "Document") -> None: + if not doc.get("file_relink_temp_docname", None): + return + attach_fields = doc.meta.get("fields", {"fieldtype": ["in", ["Attach", "Attach Image"]]}) + for df in attach_fields: + if doc.get(df.fieldname): + relink_files(doc, df.fieldname, doc.file_relink_temp_docname) + + def decode_file_content(content: bytes) -> bytes: if isinstance(content, str): content = content.encode("utf-8") diff --git a/frappe/desk/form/save.py b/frappe/desk/form/save.py index 180717da40..97dad8503d 100644 --- a/frappe/desk/form/save.py +++ b/frappe/desk/form/save.py @@ -17,6 +17,10 @@ def savedocs(doc, action): """save / submit / update doclist""" doc = frappe.get_doc(json.loads(doc)) capture_doc(doc, action) + if doc.doctype not in ["DocType", "File"] and doc.name.startswith( + "new-" + doc.doctype.lower().replace(" ", "-") + ): + doc.file_relink_temp_docname = doc.name set_local_name(doc) # action diff --git a/frappe/model/document.py b/frappe/model/document.py index 7f4758d45e..2721ebf1e7 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -10,6 +10,7 @@ from werkzeug.exceptions import NotFound import frappe from frappe import _, is_whitelisted, msgprint +from frappe.core.doctype.file.utils import relink_mismatched_files from frappe.core.doctype.server_script.server_script_utils import run_server_script_for_doc_event from frappe.desk.form.document_follow import follow_document from frappe.integrations.doctype.webhook import run_webhooks @@ -304,6 +305,7 @@ class Document(BaseDocument): if self.get("amended_from"): self.copy_attachments_from_amended_from() + relink_mismatched_files(self) self.run_post_save_methods() self.flags.in_insert = False diff --git a/frappe/public/js/frappe/model/create_new.js b/frappe/public/js/frappe/model/create_new.js index 4d1b293c78..eab684c25b 100644 --- a/frappe/public/js/frappe/model/create_new.js +++ b/frappe/public/js/frappe/model/create_new.js @@ -83,7 +83,8 @@ $.extend(frappe.model, { var cnt = frappe.model.new_name_count; if (!cnt[doctype]) cnt[doctype] = 0; cnt[doctype]++; - return frappe.router.slug(`new-${doctype}-${cnt[doctype]}`); + // random hash is added to idenity mislinked files when doc is not saved and file is uploaded. + return frappe.router.slug(`new-${doctype}-${cnt[doctype]}${frappe.utils.get_random(10)}`); }, set_default_values: function (doc, parent_doc) { diff --git a/frappe/public/js/frappe/views/breadcrumbs.js b/frappe/public/js/frappe/views/breadcrumbs.js index 93399489c1..dce726be41 100644 --- a/frappe/public/js/frappe/views/breadcrumbs.js +++ b/frappe/public/js/frappe/views/breadcrumbs.js @@ -186,7 +186,14 @@ frappe.breadcrumbs = { set_form_breadcrumb(breadcrumbs, view) { const doctype = breadcrumbs.doctype; - const docname = frappe.get_route().slice(2).join("/"); + let docname = frappe.get_route().slice(2).join("/"); + if (docname.startsWith("new-" + doctype.toLowerCase().replace(/ /g, "-"))) { + // using docname instead of doctype to include No like Doctype Name + 1, 2, 3 + docname = docname + .slice(0, -10) + .replace(/-/g, " ") + .replace(/\b\w/g, (l) => l.toUpperCase()); + } let form_route = `/app/${frappe.router.slug(doctype)}/${docname}`; this.append_breadcrumb_element(form_route, __(docname));