fix: delete child docs when parent doc is deleted (#26239)
This commit is contained in:
parent
f4fc1384a5
commit
05d7c69aa2
@ -12,10 +12,14 @@ from frappe.desk.notifications import clear_notifications
|
||||
class TransactionDeletionRecord(Document):
|
||||
def validate(self):
|
||||
frappe.only_for('System Manager')
|
||||
self.validate_doctypes_to_be_ignored()
|
||||
|
||||
def validate_doctypes_to_be_ignored(self):
|
||||
doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
|
||||
for doctype in self.doctypes_to_be_ignored:
|
||||
if doctype.doctype_name not in doctypes_to_be_ignored_list:
|
||||
frappe.throw(_("DocTypes should not be added manually to the 'Excluded DocTypes' table. You are only allowed to remove entries from it. "), title=_("Not Allowed"))
|
||||
frappe.throw(_("DocTypes should not be added manually to the 'Excluded DocTypes' table. You are only allowed to remove entries from it. "),
|
||||
title=_("Not Allowed"))
|
||||
|
||||
def before_submit(self):
|
||||
if not self.doctypes_to_be_ignored:
|
||||
@ -23,54 +27,9 @@ class TransactionDeletionRecord(Document):
|
||||
|
||||
self.delete_bins()
|
||||
self.delete_lead_addresses()
|
||||
|
||||
company_obj = frappe.get_doc('Company', self.company)
|
||||
# reset company values
|
||||
company_obj.total_monthly_sales = 0
|
||||
company_obj.sales_monthly_history = None
|
||||
company_obj.save()
|
||||
# Clear notification counts
|
||||
self.reset_company_values()
|
||||
clear_notifications()
|
||||
|
||||
singles = frappe.get_all('DocType', filters = {'issingle': 1}, pluck = 'name')
|
||||
tables = frappe.get_all('DocType', filters = {'istable': 1}, pluck = 'name')
|
||||
doctypes_to_be_ignored_list = singles
|
||||
for doctype in self.doctypes_to_be_ignored:
|
||||
doctypes_to_be_ignored_list.append(doctype.doctype_name)
|
||||
|
||||
docfields = frappe.get_all('DocField',
|
||||
filters = {
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Company',
|
||||
'parent': ['not in', doctypes_to_be_ignored_list]},
|
||||
fields=['parent', 'fieldname'])
|
||||
|
||||
for docfield in docfields:
|
||||
if docfield['parent'] != self.doctype:
|
||||
no_of_docs = frappe.db.count(docfield['parent'], {
|
||||
docfield['fieldname'] : self.company
|
||||
})
|
||||
|
||||
if no_of_docs > 0:
|
||||
self.delete_version_log(docfield['parent'], docfield['fieldname'])
|
||||
self.delete_communications(docfield['parent'], docfield['fieldname'])
|
||||
|
||||
# populate DocTypes table
|
||||
if docfield['parent'] not in tables:
|
||||
self.append('doctypes', {
|
||||
'doctype_name' : docfield['parent'],
|
||||
'no_of_docs' : no_of_docs
|
||||
})
|
||||
|
||||
# delete the docs linked with the specified company
|
||||
frappe.db.delete(docfield['parent'], {
|
||||
docfield['fieldname'] : self.company
|
||||
})
|
||||
|
||||
naming_series = frappe.db.get_value('DocType', docfield['parent'], 'autoname')
|
||||
if naming_series:
|
||||
if '#' in naming_series:
|
||||
self.update_naming_series(naming_series, docfield['parent'])
|
||||
self.delete_company_transactions()
|
||||
|
||||
def populate_doctypes_to_be_ignored_table(self):
|
||||
doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
|
||||
@ -79,6 +38,111 @@ class TransactionDeletionRecord(Document):
|
||||
'doctype_name' : doctype
|
||||
})
|
||||
|
||||
def delete_bins(self):
|
||||
frappe.db.sql("""delete from tabBin where warehouse in
|
||||
(select name from tabWarehouse where company=%s)""", self.company)
|
||||
|
||||
def delete_lead_addresses(self):
|
||||
"""Delete addresses to which leads are linked"""
|
||||
leads = frappe.get_all('Lead', filters={'company': self.company})
|
||||
leads = ["'%s'" % row.get("name") for row in leads]
|
||||
addresses = []
|
||||
if leads:
|
||||
addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
|
||||
in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
if addresses:
|
||||
addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
|
||||
|
||||
frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
|
||||
name not in (select distinct dl1.parent from `tabDynamic Link` dl1
|
||||
inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
|
||||
and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
|
||||
|
||||
frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
|
||||
and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
def reset_company_values(self):
|
||||
company_obj = frappe.get_doc('Company', self.company)
|
||||
company_obj.total_monthly_sales = 0
|
||||
company_obj.sales_monthly_history = None
|
||||
company_obj.save()
|
||||
|
||||
def delete_company_transactions(self):
|
||||
doctypes_to_be_ignored_list = self.get_doctypes_to_be_ignored_list()
|
||||
docfields = self.get_doctypes_with_company_field(doctypes_to_be_ignored_list)
|
||||
|
||||
tables = self.get_all_child_doctypes()
|
||||
for docfield in docfields:
|
||||
if docfield['parent'] != self.doctype:
|
||||
no_of_docs = self.get_number_of_docs_linked_with_specified_company(docfield['parent'], docfield['fieldname'])
|
||||
|
||||
if no_of_docs > 0:
|
||||
self.delete_version_log(docfield['parent'], docfield['fieldname'])
|
||||
self.delete_communications(docfield['parent'], docfield['fieldname'])
|
||||
self.populate_doctypes_table(tables, docfield['parent'], no_of_docs)
|
||||
|
||||
self.delete_child_tables(docfield['parent'], docfield['fieldname'])
|
||||
self.delete_docs_linked_with_specified_company(docfield['parent'], docfield['fieldname'])
|
||||
|
||||
naming_series = frappe.db.get_value('DocType', docfield['parent'], 'autoname')
|
||||
if naming_series:
|
||||
if '#' in naming_series:
|
||||
self.update_naming_series(naming_series, docfield['parent'])
|
||||
|
||||
def get_doctypes_to_be_ignored_list(self):
|
||||
singles = frappe.get_all('DocType', filters = {'issingle': 1}, pluck = 'name')
|
||||
doctypes_to_be_ignored_list = singles
|
||||
for doctype in self.doctypes_to_be_ignored:
|
||||
doctypes_to_be_ignored_list.append(doctype.doctype_name)
|
||||
|
||||
return doctypes_to_be_ignored_list
|
||||
|
||||
def get_doctypes_with_company_field(self, doctypes_to_be_ignored_list):
|
||||
docfields = frappe.get_all('DocField',
|
||||
filters = {
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Company',
|
||||
'parent': ['not in', doctypes_to_be_ignored_list]},
|
||||
fields=['parent', 'fieldname'])
|
||||
|
||||
return docfields
|
||||
|
||||
def get_all_child_doctypes(self):
|
||||
return frappe.get_all('DocType', filters = {'istable': 1}, pluck = 'name')
|
||||
|
||||
def get_number_of_docs_linked_with_specified_company(self, doctype, company_fieldname):
|
||||
return frappe.db.count(doctype, {company_fieldname : self.company})
|
||||
|
||||
def populate_doctypes_table(self, tables, doctype, no_of_docs):
|
||||
if doctype not in tables:
|
||||
self.append('doctypes', {
|
||||
'doctype_name' : doctype,
|
||||
'no_of_docs' : no_of_docs
|
||||
})
|
||||
|
||||
def delete_child_tables(self, doctype, company_fieldname):
|
||||
parent_docs_to_be_deleted = frappe.get_all(doctype, {
|
||||
company_fieldname : self.company
|
||||
}, pluck = 'name')
|
||||
|
||||
child_tables = frappe.get_all('DocField', filters = {
|
||||
'fieldtype': 'Table',
|
||||
'parent': doctype
|
||||
}, pluck = 'options')
|
||||
|
||||
for table in child_tables:
|
||||
frappe.db.delete(table, {
|
||||
'parent': ['in', parent_docs_to_be_deleted]
|
||||
})
|
||||
|
||||
def delete_docs_linked_with_specified_company(self, doctype, company_fieldname):
|
||||
frappe.db.delete(doctype, {
|
||||
company_fieldname : self.company
|
||||
})
|
||||
|
||||
def update_naming_series(self, naming_series, doctype_name):
|
||||
if '.' in naming_series:
|
||||
prefix, hashes = naming_series.rsplit('.', 1)
|
||||
@ -107,32 +171,6 @@ class TransactionDeletionRecord(Document):
|
||||
|
||||
frappe.delete_doc('Communication', communication_names, ignore_permissions=True)
|
||||
|
||||
def delete_bins(self):
|
||||
frappe.db.sql("""delete from tabBin where warehouse in
|
||||
(select name from tabWarehouse where company=%s)""", self.company)
|
||||
|
||||
def delete_lead_addresses(self):
|
||||
"""Delete addresses to which leads are linked"""
|
||||
leads = frappe.get_all('Lead', filters={'company': self.company})
|
||||
leads = ["'%s'" % row.get("name") for row in leads]
|
||||
addresses = []
|
||||
if leads:
|
||||
addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
|
||||
in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
if addresses:
|
||||
addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
|
||||
|
||||
frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
|
||||
name not in (select distinct dl1.parent from `tabDynamic Link` dl1
|
||||
inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
|
||||
and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
|
||||
|
||||
frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
|
||||
and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_doctypes_to_be_ignored():
|
||||
doctypes_to_be_ignored_list = ['Account', 'Cost Center', 'Warehouse', 'Budget',
|
||||
|
Loading…
Reference in New Issue
Block a user