From 1c4e1bc1df7e0788e235b4f735194d8567de6e58 Mon Sep 17 00:00:00 2001 From: prssanna Date: Wed, 14 Apr 2021 14:48:15 +0530 Subject: [PATCH] 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]);