def check_if_doc_is_dynamically_linked(doc, method="Delete"): '''Raise `frappe.LinkExistsError` if the document is dynamically linked''' for df in get_dynamic_link_map().get(doc.doctype, []): if df.parent in ("Communication", "ToDo", "DocShare", "Email Unsubscribe"): # don't check for communication and todo! continue meta = frappe.get_meta(df.parent) if meta.issingle: # dynamic link in single doc refdoc = frappe.db.get_singles_dict(df.parent) if (refdoc.get(df.options)==doc.doctype and refdoc.get(df.fieldname)==doc.name and ((method=="Delete" and refdoc.docstatus < 2) or (method=="Cancel" and refdoc.docstatus==1)) ): # raise exception only if # linked to an non-cancelled doc when deleting # or linked to a submitted doc when cancelling frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype, doc.name, df.parent, ""), frappe.LinkExistsError) else: # dynamic link in table for refdoc in frappe.db.sql("""select name, docstatus from `tab{parent}` where {options}=%s and {fieldname}=%s""".format(**df), (doc.doctype, doc.name), as_dict=True): if ((method=="Delete" and refdoc.docstatus < 2) or (method=="Cancel" and refdoc.docstatus==1)): # raise exception only if # linked to an non-cancelled doc when deleting # or linked to a submitted doc when cancelling frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}")\ .format(doc.doctype, doc.name, df.parent, refdoc.name), frappe.LinkExistsError)
def rename_dynamic_links(doctype, old, new): for df in get_dynamic_link_map().get(doctype, []): # dynamic link in single, just one value to check if frappe.get_meta(df.parent).issingle: refdoc = frappe.db.get_singles_dict(df.parent) if refdoc.get(df.options)==doctype and refdoc.get(df.fieldname)==old: frappe.db.sql("""update tabSingles set value=%s where field=%s and value=%s and doctype=%s""", (new, df.fieldname, old, df.parent)) else: # because the table hasn't been renamed yet! parent = df.parent if df.parent != new else old frappe.db.sql("""update `tab{parent}` set {fieldname}=%s where {options}=%s and {fieldname}=%s""".format(**df), (new, doctype, old))
def rename_dynamic_links(doctype, old, new): for df in get_dynamic_link_map().get(doctype, []): # dynamic link in single, just one value to check if frappe.get_meta(df.parent).issingle: refdoc = frappe.db.get_singles_dict(df.parent) if refdoc.get(df.options)==doctype and refdoc.get(df.fieldname)==old: frappe.db.sql("""update tabSingles set value=%s where field=%s and value=%s and doctype=%s""", (new, df.fieldname, old, df.parent)) else: # because the table hasn't been renamed yet! parent = df.parent if df.parent != new else old frappe.db.sql("""update `tab{parent}` set {fieldname}=%s where {options}=%s and {fieldname}=%s""".format(parent = parent, fieldname=df.fieldname, options=df.options), (new, doctype, old))
def check_if_doc_is_dynamically_linked(doc, method="Delete"): '''Raise `frappe.LinkExistsError` if the document is dynamically linked''' for df in get_dynamic_link_map().get(doc.doctype, []): if df.parent in ("Communication", "ToDo", "DocShare", "Email Unsubscribe", "Activity Log", 'File', 'Version', 'View Log'): # don't check for communication and todo! continue meta = frappe.get_meta(df.parent) # if meta.issingle: # # dynamic link in single doc # refdoc = frappe.db.get_singles_dict(df.parent) # if (refdoc.get(df.options) == doc.doctype # and refdoc.get(df.fieldname) == doc.name # and ((method == "Delete" and refdoc.docstatus < 2) # or (method == "Cancel" and refdoc.docstatus == 1)) # ): # # raise exception only if # # linked to an non-cancelled doc when deleting # # or linked to a submitted doc when cancelling # raise_link_exists_exception(doc, df.parent, df.parent) # else: # dynamic link in table df["table"] = ", parent, parenttype, idx" if meta.istable else "" for refdoc in frappe.db.sql( """select name, docstatus{table} from `tab{parent}` where {options}=%s and {fieldname}=%s""".format(**df), (doc.doctype, doc.name), as_dict=True): if ((method == "Delete" and refdoc.docstatus < 2) or (method == "Cancel" and refdoc.docstatus == 1)): # raise exception only if # linked to an non-cancelled doc when deleting # or linked to a submitted doc when cancelling reference_doctype = refdoc.parenttype if meta.istable else df.parent reference_docname = refdoc.parent if meta.istable else refdoc.name at_position = "at Row: {0}".format( refdoc.idx) if meta.istable else "" # raise_link_exists_exception(doc, reference_doctype, reference_docname, at_position) return reference_docname, reference_doctype return None, None
def check_if_doc_is_dynamically_linked(doc, method="Delete"): """Raise `frappe.LinkExistsError` if the document is dynamically linked""" for df in get_dynamic_link_map().get(doc.doctype, []): ignore_linked_doctypes = doc.get("ignore_linked_doctypes") or [] if df.parent in doctypes_to_skip or ( df.parent in ignore_linked_doctypes and method == "Cancel"): # don't check for communication and todo! continue meta = frappe.get_meta(df.parent) if meta.issingle: # dynamic link in single doc refdoc = frappe.db.get_singles_dict(df.parent) if (refdoc.get(df.options) == doc.doctype and refdoc.get(df.fieldname) == doc.name and ((method == "Delete" and refdoc.docstatus < 2) or (method == "Cancel" and refdoc.docstatus == 1))): # raise exception only if # linked to an non-cancelled doc when deleting # or linked to a submitted doc when cancelling raise_link_exists_exception(doc, df.parent, df.parent) else: # dynamic link in table df["table"] = ", `parent`, `parenttype`, `idx`" if meta.istable else "" for refdoc in frappe.db.sql( """select `name`, `docstatus` {table} from `tab{parent}` where {options}=%s and {fieldname}=%s""".format(**df), (doc.doctype, doc.name), as_dict=True, ): if (method == "Delete" and refdoc.docstatus < 2) or ( method == "Cancel" and refdoc.docstatus == 1): # raise exception only if # linked to an non-cancelled doc when deleting # or linked to a submitted doc when cancelling reference_doctype = refdoc.parenttype if meta.istable else df.parent reference_docname = refdoc.parent if meta.istable else refdoc.name at_position = "at Row: {0}".format( refdoc.idx) if meta.istable else "" raise_link_exists_exception(doc, reference_doctype, reference_docname, at_position)
def test_payment(self): w = self.make() from erpnext.accounts.doctype.journal_entry.test_journal_entry \ import test_records as jv_test_records jv = frappe.get_doc(frappe.copy_doc(jv_test_records[0])) jv.get("accounts")[0].reference_type = w.doctype jv.get("accounts")[0].reference_name = w.name jv.insert() jv.submit() self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 161.8) link_data = get_dynamic_link_map().get('Sales Invoice', []) link_doctypes = [d.parent for d in link_data] # test case for dynamic link order self.assertTrue(link_doctypes.index('GL Entry') > link_doctypes.index('Journal Entry Account')) jv.cancel() self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 561.8)
def check_if_doc_is_dynamically_linked(doc, method="Delete"): '''Raise `frappe.LinkExistsError` if the document is dynamically linked''' for df in get_dynamic_link_map().get(doc.doctype, []): if df.parent in ("Communication", "ToDo", "DocShare", "Email Unsubscribe", 'File', 'Version'): # don't check for communication and todo! continue meta = frappe.get_meta(df.parent) if meta.issingle: # dynamic link in single doc refdoc = frappe.db.get_singles_dict(df.parent) if (refdoc.get(df.options) == doc.doctype and refdoc.get(df.fieldname) == doc.name and ((method == "Delete" and refdoc.docstatus < 2) or (method == "Cancel" and refdoc.docstatus == 1))): # raise exception only if # linked to an non-cancelled doc when deleting # or linked to a submitted doc when cancelling frappe.throw( _('Cannot delete or cancel because {0} <a href="#Form/{0}/{1}">{1}</a> is linked with {2} <a href="#Form/{2}/{3}">{3}</a>' ).format(doc.doctype, doc.name, df.parent, ""), frappe.LinkExistsError) else: # dynamic link in table df["table"] = ", parent, parenttype, idx" if meta.istable else "" for refdoc in frappe.db.sql( """select name, docstatus{table} from `tab{parent}` where {options}=%s and {fieldname}=%s""".format(**df), (doc.doctype, doc.name), as_dict=True): if ((method == "Delete" and refdoc.docstatus < 2) or (method == "Cancel" and refdoc.docstatus == 1)): # raise exception only if # linked to an non-cancelled doc when deleting # or linked to a submitted doc when cancelling frappe.throw(_('Cannot delete or cancel because {0} <a href="#Form/{0}/{1}">{1}</a> is linked with {2} <a href="#Form/{2}/{3}">{3}</a> {4}')\ .format(doc.doctype, doc.name, refdoc.parenttype if meta.istable else df.parent, refdoc.parent if meta.istable else refdoc.name,"Row: {0}".format(refdoc.idx) if meta.istable else ""), frappe.LinkExistsError)
def check_if_doc_is_dynamically_linked(doc, method="Delete"): '''Raise `frappe.LinkExistsError` if the document is dynamically linked''' for df in get_dynamic_link_map().get(doc.doctype, []): if df.parent in ("Communication", "ToDo", "DocShare", "Email Unsubscribe", "Activity Log", 'File', 'Version'): # don't check for communication and todo! continue meta = frappe.get_meta(df.parent) if meta.issingle: # dynamic link in single doc refdoc = frappe.db.get_singles_dict(df.parent) if (refdoc.get(df.options)==doc.doctype and refdoc.get(df.fieldname)==doc.name and ((method=="Delete" and refdoc.docstatus < 2) or (method=="Cancel" and refdoc.docstatus==1)) ): # raise exception only if # linked to an non-cancelled doc when deleting # or linked to a submitted doc when cancelling raise_link_exists_exception(doc, df.parent, df.parent) else: # dynamic link in table df["table"] = ", parent, parenttype, idx" if meta.istable else "" for refdoc in frappe.db.sql("""select name, docstatus{table} from `tab{parent}` where {options}=%s and {fieldname}=%s""".format(**df), (doc.doctype, doc.name), as_dict=True): if ((method=="Delete" and refdoc.docstatus < 2) or (method=="Cancel" and refdoc.docstatus==1)): # raise exception only if # linked to an non-cancelled doc when deleting # or linked to a submitted doc when cancelling reference_doctype = refdoc.parenttype if meta.istable else df.parent reference_docname = refdoc.parent if meta.istable else refdoc.name at_position = "at Row: {0}".format(refdoc.idx) if meta.istable else "" raise_link_exists_exception(doc, reference_doctype, reference_docname, at_position)
def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False, ignore_permissions=False, flags=None, ignore_on_trash=False): """ Deletes a doc(dt, dn) and validates if it is not submitted and not linked in a live record """ if not ignore_doctypes: ignore_doctypes = [] # get from form if not doctype: doctype = frappe.form_dict.get('dt') name = frappe.form_dict.get('dn') names = name if isinstance(name, basestring): names = [name] for name in names or []: # already deleted..? if not frappe.db.exists(doctype, name): return # delete attachments remove_all(doctype, name) doc = None if doctype == "DocType": if for_reload: try: doc = frappe.get_doc(doctype, name) except frappe.DoesNotExistError: pass else: doc.run_method("before_reload") else: frappe.db.sql("delete from `tabCustom Field` where dt = %s", name) frappe.db.sql("delete from `tabCustom Script` where dt = %s", name) frappe.db.sql( "delete from `tabProperty Setter` where doc_type = %s", name) frappe.db.sql("delete from `tabReport` where ref_doctype=%s", name) delete_from_table(doctype, name, ignore_doctypes, None) else: doc = frappe.get_doc(doctype, name) if not for_reload: if ignore_permissions: if not flags: flags = {} flags["ignore_permissions"] = ignore_permissions if flags: doc.flags.update(flags) check_permission_and_not_submitted(doc) if not ignore_on_trash: doc.run_method("on_trash") dynamic_linked_doctypes = [ df.parent for df in get_dynamic_link_map().get(doc.doctype, []) ] if "ToDo" in dynamic_linked_doctypes: delete_linked_todos(doc) if "Communication" in dynamic_linked_doctypes: delete_linked_communications(doc) if "DocShare" in dynamic_linked_doctypes: delete_shared(doc) if "Email Unsubscribe" in dynamic_linked_doctypes: delete_email_subscribe(doc) # check if links exist if not force: check_if_doc_is_linked(doc) check_if_doc_is_dynamically_linked(doc) update_naming_series(doc) delete_from_table(doctype, name, ignore_doctypes, doc) doc.run_method("after_delete") if doc: try: doc.notify_update() insert_feed(doc) except ImportError: pass # delete user_permissions frappe.defaults.clear_default(parenttype="User Permission", key=doctype, value=name)
def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False, ignore_permissions=False, flags=None, ignore_on_trash=False): """ Deletes a doc(dt, dn) and validates if it is not submitted and not linked in a live record """ if not ignore_doctypes: ignore_doctypes = [] # get from form if not doctype: doctype = frappe.form_dict.get('dt') name = frappe.form_dict.get('dn') names = name if isinstance(name, basestring): names = [name] for name in names or []: # already deleted..? if not frappe.db.exists(doctype, name): return # delete attachments remove_all(doctype, name) doc = None if doctype=="DocType": if for_reload: try: doc = frappe.get_doc(doctype, name) except frappe.DoesNotExistError: pass else: doc.run_method("before_reload") else: frappe.db.sql("delete from `tabCustom Field` where dt = %s", name) frappe.db.sql("delete from `tabCustom Script` where dt = %s", name) frappe.db.sql("delete from `tabProperty Setter` where doc_type = %s", name) frappe.db.sql("delete from `tabReport` where ref_doctype=%s", name) delete_from_table(doctype, name, ignore_doctypes, None) else: doc = frappe.get_doc(doctype, name) if not for_reload: if ignore_permissions: if not flags: flags = {} flags["ignore_permissions"] = ignore_permissions if flags: doc.flags.update(flags) check_permission_and_not_submitted(doc) if not ignore_on_trash: doc.run_method("on_trash") dynamic_linked_doctypes = [df.parent for df in get_dynamic_link_map().get(doc.doctype, [])] if "ToDo" in dynamic_linked_doctypes: delete_linked_todos(doc) if "Communication" in dynamic_linked_doctypes: delete_linked_communications(doc) if "DocShare" in dynamic_linked_doctypes: delete_shared(doc) if "Email Unsubscribe" in dynamic_linked_doctypes: delete_email_subscribe(doc) # check if links exist if not force: check_if_doc_is_linked(doc) check_if_doc_is_dynamically_linked(doc) update_naming_series(doc) delete_from_table(doctype, name, ignore_doctypes, doc) doc.run_method("after_delete") if doc: try: doc.notify_update() insert_feed(doc) except ImportError: pass # delete user_permissions frappe.defaults.clear_default(parenttype="User Permission", key=doctype, value=name)